home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 1992 August / info-mac-1992.iso / UNIX / Mcvert 1.83.shar < prev    next >
Text File  |  1992-08-29  |  75KB  |  2,387 lines

  1. 10-Aug-92 20:30:19-GMT,75337;000000000201
  2. Received: from SUMEX-AIM.Stanford.EDU by CAMIS.Stanford.EDU (4.1/inc-1.0)
  3.     id AA15860; Mon, 10 Aug 92 13:30:14 PDT
  4. Full-Name: Info-Mac Moderator
  5. Received: by SUMEX-AIM.Stanford.EDU (4.1/inc-1.0)
  6.     id AA11539; Mon, 10 Aug 92 13:30:09 PDT
  7. Resent-Message-Id: <9208102030.AA11539@SUMEX-AIM.Stanford.EDU>
  8. Return-Path: <mntgfx!std.MENTORG.COM!jskudlarek@uunet.UU.NET> 
  9. Received: from relay2.UU.NET by CAMIS.Stanford.EDU (4.1/inc-1.0) id AA13868;
  10.         Mon, 10 Aug 92 12:05:16 PDT 
  11. Received: from uunet.uu.net (via LOCALHOST.UU.NET) by relay2.UU.NET with SMTP
  12.         (5.61/UUNET-internet-primary) id AA23142; Mon, 10 Aug 92 15:03:49
  13.         -0400 
  14. Received: from mntgfx.UUCP by uunet.uu.net with UUCP/RMAIL (queueing-rmail)
  15.         id 145834.2213; Mon, 10 Aug 1992 14:58:34 EDT 
  16. Received: by pdx.MENTORG.COM ( 5.52 (84)/DontTreadOnMe) id AA21558; Mon, 10
  17.         Aug 92 10:38:47 PDT 
  18. Received: by std.MENTORG.COM (5.65c/smail2.5/09-24-87/Mentor) id AA16473;
  19.         Mon, 10 Aug 1992 10:40:51 -0700 
  20. Date: Mon, 10 Aug 1992 10:40:51 -0700 
  21. From: jskudlarek@std.MENTORG.COM (Joseph Skudlarek)
  22. Message-Id: <199208101740.AA16473@std.MENTORG.COM> 
  23. To: info-mac@sumex-aim.stanford.edu
  24. Subject: mcvert-183.shar 
  25. Resent-To: backmod@SUMEX-AIM.Stanford.EDU
  26. Resent-Date: Mon, 10 Aug 1992 13:30:03 PDT
  27. Resent-From: Info-Mac Moderator <macmod@sumex-aim.Stanford.EDU>
  28.  
  29. mcvert, written in C, runs under UNIX and converts between Macintosh
  30. file formats including BinHex4.0 and MacBinary.  See mcvert.1 (the man
  31. page) for details.
  32.  
  33. Please replace mcvert-182.shar with mcvert-183.shar, which follows.
  34. The the current usage and the additional changes since 1.82 are
  35. detailed below.
  36.  
  37. Usage: mcvert { [options] name ...} ...
  38.  default:
  39.     -xDqv
  40.  
  41.  option:
  42.     -x    BinHex      .hqx     <-> MacBinary
  43.     -r    Resource    .rsrc    <-> MacBinary
  44.     -d    Data        .data    <-> MacBinary
  45.     -u    Text(trans) .text    <-> MacBinary
  46.     -h    Host(as is) .text    <-> MacBinary
  47.  
  48.     -D    Download (Other -> MacBinary)
  49.     -U    Upload (MacBinary -> Other)
  50.  
  51.     -p    BinHex -> MacBinary => unpack PIT
  52.     -q    disable unpack PIT
  53.  
  54.     -s    silent
  55.     -S    Silent about ``Converting ... '' lines too
  56.     -v    verbose
  57.     -V    Verbose, includes debugging information
  58.  
  59. Environment:
  60.     MAC_EDITOR        MACA    Mac creator for text files
  61.     MAC_DLOAD_DIR     .       directory for -D files
  62.     MAC_EXT           .bin    extension for -D files
  63.     MAC_LINE_LIMIT    none    maximum line length for -Ux files
  64.  
  65.  * ----------------------------------------------------------------------------
  66.  *    External
  67.  *    -----
  68.  *        relax exactly 64 characters per incoming hqx file, and
  69.  *        handle files without trailing newline, so, eg, 
  70.  *            Telnet2.5docs.sit.hqx now converts correctly (failure
  71.  *            reported by Justin Sullivan <justin@f2.facts.uky.edu>)
  72.  *    now also processes info-mac/app/road-map.hqx correctly
  73.  *       (failure reported by Victor Norton<norton@andy.bgsu.edu>)
  74.  *        rework the man page for improved clarity and completeness
  75.  * -----
  76.  * Internal
  77.  * -----
  78.  *        avoid warning message from gcc on Sequent Balance mainframe
  79.  *            reported by Justin Sullivan <justin@f2.facts.uky.edu>
  80.  *        bump max incoming line length to 2048 from 255
  81.  *        add mcvert.ps target to Makefile
  82.  * -----
  83.  * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  84.  * (503) 685-1576 (work)
  85.  * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
  86.  * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  87.  * Version 1.83 03Aug92
  88.  * ----------------------------------------------------------------------------
  89.  
  90. #!/bin/sh
  91. # This is a shell archive (shar 3.47)
  92. # made 08/10/1992 17:34 UTC by jskudlarek@hal
  93. # Source directory //hal/local_user/jskudlarek/notes/info-mac/mcvert
  94. #
  95. # existing files will NOT be overwritten unless -c is specified
  96. #
  97. # This shar contains:
  98. # length  mode       name
  99. # ------ ---------- ------------------------------------------
  100. #  19826 -r--r--r-- mcvert.c
  101. #  23244 -r--r--r-- hqxify.c
  102. #   6096 -r--r--r-- unpack.c
  103. #   9603 -r--r--r-- mactypes.h
  104. #   1108 -r--r--r-- Makefile
  105. #   7376 -r--r--r-- mcvert.1
  106. #
  107. # ============= mcvert.c ==============
  108. if test -f 'mcvert.c' -a X"$1" != X"-c"; then
  109.     echo 'x - skipping mcvert.c (File already exists)'
  110. else
  111. echo 'x - extracting mcvert.c (Text)'
  112. sed 's/^X//' << 'SHAR_EOF' > 'mcvert.c' &&
  113. /**
  114. X * mcvert.c - version 1.05 - 10 January, 1990
  115. X * Written by Doug Moore - Rice University - dougm@rice.edu - April '87
  116. X
  117. X * Sun bug fixes, assorted stuff - Jim Sasaki, March '89
  118. X
  119. X * Changed default max_line_size from 2000 to unlimited - Doug Moore, April, '89
  120. X
  121. X * Sun 3/60 doesn't like odd-sized structs.  Bug fixed - Doug Moore, April, '89
  122. X *                                              - aided by Spencer W. Thomas
  123. X
  124. X * Didn't handle properly many hqx files combined in one file.  Bug fixed -
  125. X *                                           Doug Moore, June, '89
  126. X
  127. X * Modified to handle MacBinaryII specification. Jim Van Verth, Sept, '89
  128. X
  129. X * Fixed a bug when there are blank lines in hqx data, as happens when newline
  130. X * get translated to CRLF and then to \n\n, common for some file transfers.
  131. X * The last hqx line would be lost if the previous line was blank or junk.
  132. X *    Glenn Trewitt, Stanford University, 1990    (1.05)
  133. X
  134. X * Fixed a bug that occurred when extracting data or resource
  135. X * forks on a Sun 4.  It was a byte alignment problem.
  136. X * Rick Zaccone, zaccone@bucknell.edu.  April 1991.  Version 1.6
  137. X
  138. X * Fixed:
  139. X *   Sent all "Converting ... " lines to stdout instead of stderr
  140. X *   Changed mactypes.h for HP-UX systems
  141. X *      Alan Danziger, aland@cs.brandeis.edu.  October 1991. Version 1.6.5
  142. X
  143. X * ----------------------------------------------------------------------------
  144. X * External
  145. X * -----
  146. X * Fixed buffering bug when converting very small MacBinary files to hqx files.
  147. X * Provide helpful usage line.
  148. X * Control "Converting ... " lines separately with -S flag.
  149. X * Make encoding and decoding consistent by ignoring locked and init flags.
  150. X * Clean up some error messages; check for more errors; provide errno on error.
  151. X * Updated the man page.
  152. X * -----
  153. X * Internal
  154. X * -----
  155. X * Reformat source (sorry, local standard used by tools is tab space == 3)
  156. X * Remove compiler warning messages.
  157. X * Rename some variables.
  158. X * Added some comments to code.
  159. X * Added some offsets to struct definitions.
  160. X * Since the makefile has compilation flags,
  161. X *        make the compiles depend on the Makefile.
  162. X * -----
  163. X * Thanks to all who have gone before for creating, maintaining,
  164. X * improving, and providing this program and documentation.
  165. X * -----
  166. X * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  167. X * {Jskud@std.mentorg.com,Joseph_Skudlarek@mentorg.com}
  168. X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  169. X * Version 1.70 09Jul92
  170. X * ----------------------------------------------------------------------------
  171. X
  172. X * ----------------------------------------------------------------------------
  173. X * External
  174. X * -----
  175. X *   Added -V (Verbose) option (includes debugging information)
  176. X *   Fixed bug converting hqx to MacBinary if last line is ":"
  177. X *   Avoided a silent error and quick exit situation.
  178. X * -----
  179. X * Internal
  180. X * -----
  181. X *   Got rid of almost all lint (SunOS and HP-UX) error messages.
  182. X *   Compiled on SunOs, HP-UX, DomainOS.
  183. X *   Incorporated Parag Patel <parag@netcom.com> changes for AU/X.
  184. X *     Here's some diffs for really quick cheap hacks to get mcvert to compile
  185. X *     and run under A/UX.  The main problem was that timeb does not exist, so
  186. X *     I added 2 #ifdef TIMEVAL to use the System-V timeval package instead.
  187. X *     The Makefile just has a -DTIMEVAL and a magic -U_SYSV_SOURCE to get
  188. X *     around a pre-defined type "ulong" in sys/types.h (thanks to Apple).
  189. X *   Did more code overhauling:
  190. X *      add lots more comments, rename variables, reformat source.
  191. X *   Put code in un_hqx to avoid suspected buffering problem.
  192. X * -----
  193. X * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  194. X * (503) 685-1576 (work)
  195. X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
  196. X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  197. X * Version 1.80 15Jul92
  198. X * ----------------------------------------------------------------------------
  199. X
  200. X * ----------------------------------------------------------------------------
  201. X * External
  202. X * -----
  203. X *        Made hqx file scan processing much smarter
  204. X *            so, for example, info-mac/comm/qwk-reader.hqx,
  205. X *            complete with extraneous colons in column one, converts correctly
  206. X *            (problem described by Edward John Sabol <es2j+@andrew.cmu.edu>)
  207. X *        Avoid silly perror on usage message (prompted by Edward John Sabol)
  208. X *        Improve error message regarding improper format
  209. X *        Added more caveats to man page
  210. X * -----
  211. X * Internal
  212. X * -----
  213. X *        Fixed typo's in printf lines to pass all expected arguments
  214. X *            (pointed out by Bo Holst-Christensen
  215. X *                [holst@diku.dk/dikubhc1@uts.uni-c.dk/holst@login.dkuug.dk])
  216. X *        Tweak Makefile to ease shar creation and special case ulong, not A/UX
  217. X *        Add yet more comments and debugging code
  218. X * -----
  219. X * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  220. X * (503) 685-1576 (work)
  221. X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
  222. X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  223. X * Version 1.82 30Jul92
  224. X * ----------------------------------------------------------------------------
  225. X
  226. X * ----------------------------------------------------------------------------
  227. X *    External
  228. X *    -----
  229. X *        relax exactly 64 characters per incoming hqx file, and
  230. X *        handle files without trailing newline, so, eg, 
  231. X *            Telnet2.5docs.sit.hqx now converts correctly (failure
  232. X *            reported by Justin Sullivan <justin@f2.facts.uky.edu>)
  233. X *    now also processes info-mac/app/road-map.hqx correctly
  234. X *       (failure reported by Victor Norton<norton@andy.bgsu.edu>)
  235. X *        rework the man page for improved clarity and completeness
  236. X * -----
  237. X * Internal
  238. X * -----
  239. X *        avoid warning message from gcc on Sequent Balance mainframe
  240. X *            reported by Justin Sullivan <justin@f2.facts.uky.edu>
  241. X *        bump max incoming line length to 2048 from 255
  242. X *        add mcvert.ps target to Makefile
  243. X * -----
  244. X * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  245. X * (503) 685-1576 (work)
  246. X * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
  247. X * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  248. X * Version 1.83 03Aug92
  249. X * ----------------------------------------------------------------------------
  250. X
  251. X * ----------------------------------------------------------------------------
  252. X * This program may be freely distributed for non-profit purposes.  It may not
  253. X * be sold, by itself or as part of a collection of software.  It may be freely
  254. X * modified as long as no modified version is distributed.  Modifications of
  255. X * interest to all can be incorporated into the program by sending them to me
  256. X * for distribution.  Parts of the code can be used in other programs.  I am not
  257. X * responsible for any damage caused by this program.  I hope you enjoy it.
  258. X *
  259. X * ----------
  260. X * Things that yet could be done:
  261. X *        provide "verify only" mode which would read and report but
  262. X *        not write any files -- useful for verifying formats
  263. X *        and for finding out the names of the files which
  264. X *        would be created.
  265. X * ----------
  266. X */
  267. X
  268. /*
  269. X * Naming
  270. X *        DOWNLOAD
  271. X *            => converting TO MacBinary
  272. X *            => direction == FORWARDS
  273. X *            => use un_* routines (un => UNdo encoding?)
  274. X *        UPLOAD
  275. X *            => converting FROM MacBinary
  276. X *            => direction == BACKWARDS
  277. X *            => use re_* routines (re => Really Encode?)
  278. X */
  279. X
  280. #include "mactypes.h"
  281. X
  282. #define HQX 0
  283. #define TEXT 1
  284. #define DATA 2
  285. #define RSRC 3
  286. #define HOST 4
  287. #define FORWARDS 0
  288. #define BACKWARDS 1
  289. X
  290. FILE *verbose;
  291. FILE *debug;
  292. FILE *convert;
  293. FILE *devnull;
  294. FILE *output;
  295. X
  296. char **hqxnames, **hqxnames_left;
  297. char *dir, *ext, *text_author;
  298. char *maxlines_str;
  299. int maxlines;
  300. X
  301. char Usage[] = "\
  302. Usage: %s { [options] name ...} ...\n\
  303. X default:\n\
  304. \t-xDqv\n\
  305. \n\
  306. X option:\n\
  307. \t-x\tBinHex      .hqx \t<-> MacBinary\n\
  308. \t-r\tResource    .rsrc\t<-> MacBinary\n\
  309. \t-d\tData        .data\t<-> MacBinary\n\
  310. \t-u\tText(trans) .text\t<-> MacBinary\n\
  311. \t-h\tHost(as is) .text\t<-> MacBinary\n\
  312. \n\
  313. \t-D\tDownload (Other -> MacBinary)\n\
  314. \t-U\tUpload (MacBinary -> Other)\n\
  315. \n\
  316. \t-p\tBinHex -> MacBinary => unpack PIT\n\
  317. \t-q\tdisable unpack PIT\n\
  318. \n\
  319. \t-s\tsilent\n\
  320. \t-S\tSilent about ``Converting ... '' lines too\n\
  321. \t-v\tverbose\n\
  322. \t-V\tVerbose, includes debugging information\n\
  323. \n\
  324. Environment:\n\
  325. \tMAC_EDITOR    \tMACA\tMac creator for text files\n\
  326. \tMAC_DLOAD_DIR \t.   \tdirectory for -D files\n\
  327. \tMAC_EXT       \t.bin\textension for -D files\n\
  328. \tMAC_LINE_LIMIT\tnone\tmaximum line length for -Ux files\n\
  329. ";
  330. X
  331. char *cmdname;
  332. X
  333. main(argc, argv)
  334. X    int argc;
  335. X    char **argv;
  336. {
  337. X    char *flags, *getenv();
  338. X    int direction, mode, unpit_flag;
  339. X
  340. X    cmdname = argv[0];
  341. X
  342. X    /* Early error and clean exit if missing arguments */
  343. X    if (argc < 2) {
  344. X        usage();
  345. X        /*NOTREACHED*/
  346. X    }
  347. X
  348. X    devnull = fopen("/dev/null", "w");
  349. X
  350. X    argv++;
  351. X    argc--;
  352. X    verbose = stderr;
  353. X    debug = devnull;
  354. X    output = stdout;
  355. X    convert = stdout;
  356. X    direction = FORWARDS;
  357. X    mode = HQX;
  358. X    unpit_flag = 0;
  359. X
  360. X    if ((text_author = getenv("MAC_EDITOR")) == NULL)
  361. X        text_author = "MACA";
  362. X    if ((ext = getenv("MAC_EXT")) == NULL)
  363. X        ext = ".bin";
  364. X    if ((dir = getenv("MAC_DLOAD_DIR")) == NULL)
  365. X        dir = ".";
  366. X    if ((maxlines_str = getenv("MAC_LINE_LIMIT")) == NULL)
  367. X        maxlines = 0;
  368. X    else {
  369. X        maxlines = atoi(maxlines_str);
  370. X        if (maxlines < MIN_HQX_LINES) {
  371. X            fprintf(stderr, "%s: %s; was %d; reset to %d\n",
  372. X                cmdname,
  373. X                "warning: MAC_LINE_LIMIT too small",
  374. X                maxlines, MIN_HQX_LINES);
  375. X            maxlines = MIN_HQX_LINES;
  376. X        }
  377. X    }
  378. X
  379. X    /* Make command line arguments globally accessible */
  380. X    hqxnames = (char **) calloc((unsigned)argc + 1, sizeof(char *));
  381. X    hqxnames_left = hqxnames;
  382. X    while (argc--)
  383. X        *hqxnames_left++ = *argv++;
  384. X
  385. X    /* Flag the end of the list */
  386. X    *hqxnames_left = "-";
  387. X    hqxnames_left = hqxnames;
  388. X
  389. X    /* While not at the end of the list */
  390. X    while (strcmp(*hqxnames_left, "-")) {
  391. X        if (hqxnames_left[0][0] == '-') {
  392. X            flags = *hqxnames_left++;
  393. X            while (*++flags)
  394. X                switch (*flags) {
  395. X                case 'x':
  396. X                    mode = HQX;
  397. X                    break;
  398. X                case 'u':
  399. X                    mode = TEXT;
  400. X                    break;
  401. X                case 'd':
  402. X                    mode = DATA;
  403. X                    break;
  404. X                case 'r':
  405. X                    mode = RSRC;
  406. X                    break;
  407. X                case 'h':
  408. X                    mode = HOST;
  409. X                    break;
  410. X                case 'D':
  411. X                    direction = FORWARDS;
  412. X                    break;
  413. X                case 'U':
  414. X                    direction = BACKWARDS;
  415. X                    break;
  416. X                case 'q':
  417. X                    unpit_flag = 0;
  418. X                    break;
  419. X                case 'p':
  420. X                    unpit_flag = 1;
  421. X                    break;
  422. X                case 'S':
  423. X                    convert = devnull;
  424. X                    /* FALLTHRU */
  425. X                case 's':
  426. X                    verbose = devnull;
  427. X                    break;
  428. X                case 'v':
  429. X                    verbose = stderr;
  430. X                    break;
  431. X                case 'V':
  432. X                    debug = stderr;
  433. X                    break;
  434. X                default:
  435. X                    usage();
  436. X                    /*NOTREACHED*/
  437. X                }
  438. X        }
  439. X        if (direction == BACKWARDS)
  440. X            if (mode == HQX && unpit_flag)
  441. X                re_hqx();      /* no re_pit() yet */
  442. X            else if (mode == HQX)
  443. X                re_hqx();
  444. X            else
  445. X                re_other(mode);
  446. X        else if (mode == HQX)
  447. X            un_hqx(unpit_flag);
  448. X        else
  449. X            un_other(mode);
  450. X    }
  451. X
  452. X    exit(0);
  453. X    /*NOTREACHED*/
  454. }
  455. X
  456. /* An array useful for CRC calculations that use 0x1021 as the "seed" */
  457. word magic[] = {
  458. X    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  459. X    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  460. X    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  461. X    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  462. X    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  463. X    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  464. X    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  465. X    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  466. X    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  467. X    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  468. X    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  469. X    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  470. X    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  471. X    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  472. X    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  473. X    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  474. X    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  475. X    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  476. X    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  477. X    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  478. X    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  479. X    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  480. X    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  481. X    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  482. X    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  483. X    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  484. X    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  485. X    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  486. X    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  487. X    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  488. X    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  489. X    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  490. };
  491. X
  492. X
  493. /*
  494. X * calc_crc() --
  495. X *   Compute the MacBinary II-style CRC for the data pointed to by p, with the
  496. X *   crc seeded to seed.
  497. X *
  498. X *   Modified by Jim Van Verth to use the magic array for efficiency.
  499. X */
  500. short
  501. calc_mb_crc(p, len, seed)
  502. X    unsigned char *p;
  503. X    long len;
  504. X    short seed;
  505. {
  506. X    short hold;        /* crc computed so far */
  507. X    long i;            /* index into data */
  508. X
  509. X    extern unsigned short magic[];    /* the magic array */
  510. X
  511. X    hold = seed;                   /* start with seed */
  512. X    for (i = 0; i < len; i++, p++) {
  513. X        hold ^= (*p << 8);
  514. X        hold = (hold << 8) ^ magic[(unsigned char) (hold >> 8)];
  515. X    }
  516. X
  517. X    return (hold);
  518. }                /* calc_crc() */
  519. X
  520. X
  521. /* Report a fatal error */
  522. error(msg, name)
  523. X    char msg[], name[];
  524. X
  525. {
  526. X    fprintf(stderr, msg, name);
  527. X    putc('\n', stderr);
  528. X    perror("\nlast perror (may not be relevent)");
  529. X    fprintf(stderr, "%s: exiting\n", cmdname);
  530. X    exit(2);
  531. X    /*NOTREACHED*/
  532. }
  533. X
  534. /* replace illegal Unix characters in file name */
  535. /* make sure host file name doesn't get truncated beyond recognition */
  536. unixify(np)
  537. X    register char *np;
  538. {
  539. X    register ulong c;
  540. X
  541. X    c = strlen(np);
  542. X    if (c > SYSNAMELEN - 4)
  543. X        c = SYSNAMELEN - 4;
  544. X    np[c] = '\0';
  545. X    np--;
  546. X    while (c = *++np)
  547. X        if (c <= ' ' || c == '/' || c > '~')
  548. X            *np = '_';
  549. }
  550. X
  551. /* Convert Unix time (GMT since 1-1-1970) to Mac time (local since 1-1-1904) */
  552. #define MACTIMEDIFF 0x7c25b080    /* Mac time of 00:00:00 GMT, Jan 1, 1970 */
  553. X
  554. X
  555. ulong
  556. time2mac(xtime)
  557. X    ulong xtime;
  558. {
  559. #ifdef TIMEVAL
  560. X    struct timeval t;
  561. X    struct timezone tz;
  562. X
  563. X    gettimeofday(&t, &tz);
  564. X    return long2mac(xtime + MACTIMEDIFF
  565. X       - 60 * (tz.tz_minuteswest - 60 * tz.tz_dsttime));
  566. #else
  567. X    struct timeb tp;
  568. X
  569. X    ftime(&tp);
  570. X    return long2mac(xtime + MACTIMEDIFF
  571. X        - 60 * (tp.timezone - 60 * tp.dstflag));
  572. #endif
  573. }
  574. X
  575. /* This procedure copies the input file to the output file, basically, although
  576. X    in TEXT mode it changes LF's to CR's and in any mode it forges a Mac info
  577. X    header.  Author type for TEXT mode can come from the MAC_EDITOR environ-
  578. X    ment variable if it is defined. */
  579. X
  580. un_other(mode)
  581. X    int mode;
  582. {
  583. X    register ulong b;
  584. X    register ulong nchars;
  585. X    char txtfname[BINNAMELEN], binfname[BINNAMELEN];
  586. X    FILE *txtfile, *binfile;
  587. X    char *suffix;
  588. X    struct stat stbuf;
  589. X    info_header info;
  590. X    int extra_chars;
  591. X    ulong dlen, rlen, mtim, ctim;
  592. X    short crc, calc_mb_crc();
  593. X
  594. X    if (mode == DATA)
  595. X        suffix = ".data";
  596. X    else if (mode == RSRC)
  597. X        suffix = ".rsrc";
  598. X    else
  599. X        suffix = ".text";
  600. X
  601. X    while (hqxnames_left[0][0] != '-') {
  602. X
  603. X        strcpy(txtfname, *hqxnames_left++);
  604. X        if (!(txtfile = fopen(txtfname, "r"))) {
  605. X            /*
  606. X             * Maybe we are supposed to figure out the suffix
  607. X             * ourselves?
  608. X             */
  609. X            strcat(txtfname, suffix);
  610. X            if (!(txtfile = fopen(txtfname, "r")))
  611. X                error("Cannot open %s", txtfname);
  612. X        }
  613. X        if (stat(txtfname, &stbuf))
  614. X            error("Cannot read %s", txtfname);
  615. X
  616. X        /* stuff header data into the info header */
  617. X        bzero((char*)&info, sizeof(info_header));
  618. X        info.nlen = strlen(txtfname);
  619. X        info.nlen = (info.nlen > NAMELEN) ? NAMELEN : info.nlen;
  620. X        info.name[info.nlen] = '\0';
  621. X        strcpy((char*)info.name, txtfname);   /* name */
  622. X        mtim = time2mac((ulong)stbuf.st_mtime);
  623. X        ctim = time2mac((ulong)stbuf.st_ctime);
  624. X        bcopy((char*)&mtim, (char*)info.mtim, 4);
  625. X        bcopy((char*)&ctim, (char*)info.ctim, 4);
  626. X        info.uploadvers = '\201';
  627. X        info.readvers = '\201';
  628. X
  629. X        if (mode == RSRC) {
  630. X            /* dlen is already zero */
  631. X            rlen = long2mac(stbuf.st_size);
  632. X            bcopy((char*)&rlen, (char*)info.rlen, 4);
  633. X            bcopy("APPL", (char*)info.type, 4);
  634. X            bcopy("CCOM", (char*)info.auth, 4);
  635. X        } else {
  636. X            dlen = long2mac(stbuf.st_size);
  637. X            bcopy((char*)&dlen, (char*)info.dlen, 4);
  638. X            /* rlen is already zero */
  639. X            bcopy("TEXT", (char*)info.type, 4);
  640. X            if (mode == DATA)
  641. X                bcopy("????", (char*)info.auth, 4);
  642. X            else
  643. X                bcopy(text_author, (char*)info.auth, 4);
  644. X        }
  645. X
  646. X        /* calculate CRC */
  647. X        crc = calc_mb_crc((unsigned char*)&info, 124L, 0);
  648. X        info.crc[0] = (char) (crc >> 8);
  649. X        info.crc[1] = (char) crc;
  650. X
  651. X        /* Create the .bin file and write the info to it */
  652. X        sprintf(binfname, "%s/%s%s", dir, txtfname, ext);
  653. X        if ((binfile = fopen(binfname, "w")) == NULL)
  654. X            error("Cannot open %s", binfname);
  655. X        fprintf(convert,
  656. X            "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  657. X            txtfname, info.type, info.auth);
  658. X        fwrite((char*)&info, sizeof(info), 1, binfile);
  659. X
  660. X        nchars = stbuf.st_size;
  661. X        extra_chars = 127 - (nchars + 127) % 128;
  662. X        if (mode == TEXT)
  663. X            while (nchars--) {
  664. X                b = getc(txtfile);
  665. X                if (b == LF)
  666. X                    b = CR;
  667. X                putc((char)b, binfile);
  668. X            }
  669. X        else
  670. X            while (nchars--)
  671. X                putc(getc(txtfile), binfile);
  672. X
  673. X        while (extra_chars--)
  674. X            putc(0, binfile);
  675. X        fclose(binfile);
  676. X        fclose(txtfile);
  677. X    }
  678. }
  679. X
  680. /* This procedure copies the input file to the output file, basically, although
  681. X    in TEXT mode it changes CR's to LF's and in any mode it skips over the Mac
  682. X    info header. */
  683. X
  684. re_other(mode)
  685. X    int mode;
  686. {
  687. X    register ulong b;
  688. X    register ulong nchars;
  689. X    ulong temp;
  690. X    char txtfname[BINNAMELEN], binfname[BINNAMELEN];
  691. X    FILE *txtfile, *binfile;
  692. X    char *suffix;
  693. X    info_header info;
  694. X
  695. X    if (mode == DATA)
  696. X        suffix = ".data";
  697. X    else if (mode == RSRC)
  698. X        suffix = ".rsrc";
  699. X    else
  700. X        suffix = ".text";
  701. X
  702. X    while (hqxnames_left[0][0] != '-') {
  703. X
  704. X        strcpy(binfname, *hqxnames_left++);
  705. X        if ((binfile = fopen(binfname, "r")) == NULL) {
  706. X            /*
  707. X             * Maybe we are supposed to figure out the suffix
  708. X             * ourselves?
  709. X             */
  710. X            strcat(binfname, ext);
  711. X            if (!(binfile = fopen(binfname, "r")))
  712. X                error("Cannot open %s", binfname);
  713. X        }
  714. X        /* Read the info from the .bin file, create the output file */
  715. X        fread((char*)&info, sizeof(info), 1, binfile);
  716. X        strncpy(txtfname, (char*)info.name, (int)info.nlen);
  717. X        txtfname[info.nlen] = '\0';
  718. X        fprintf(convert,
  719. X            "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  720. X            txtfname, info.type, info.auth);
  721. X
  722. X        /*
  723. X         * It appears that we use the unadorned name if possible,
  724. X         * and only add the suffix to avoid collisions.
  725. X         * This seems silly to me today (30Jul92), but
  726. X         * it looks deliberate, and we're avoiding gratuitous changes,
  727. X         * so we leave it as it is.
  728. X         */
  729. X        if ((txtfile = fopen(txtfname, "r")) == NULL) {
  730. X            if ((txtfile = fopen(txtfname, "w")) == NULL)
  731. X                error("Cannot open %s", txtfname);
  732. X        } else {
  733. X            fclose(txtfile);
  734. X            strcat(txtfname, suffix);
  735. X            if ((txtfile = fopen(txtfname, "w")) == NULL)
  736. X                error("Cannot open %s", txtfname);
  737. X        }
  738. X
  739. X        bcopy((char*)info.dlen, (char *) &temp, 4);
  740. X        nchars = temp;
  741. X        if (mode == TEXT)
  742. X            while (nchars--) {
  743. X                b = getc(binfile);
  744. X                if (b == CR)
  745. X                    b = LF;
  746. X                putc((char)b, txtfile);
  747. X            }
  748. X        else if (mode == DATA)
  749. X            while (nchars--)
  750. X                putc(getc(binfile), txtfile);
  751. X        else {
  752. X            while (nchars--)
  753. X                getc(binfile);
  754. X            bcopy((char*)info.rlen, (char *) &temp, 4);
  755. X            nchars = temp;
  756. X            while (nchars--)
  757. X                putc(getc(binfile), txtfile);
  758. X        }
  759. X
  760. X        fclose(binfile);
  761. X        fclose(txtfile);
  762. X    }
  763. }
  764. X
  765. usage()
  766. {
  767. X    fprintf(stderr, Usage, cmdname);
  768. X    exit(1);
  769. X    /*NOTREACHED*/
  770. }
  771. X    
  772. SHAR_EOF
  773. chmod 0444 mcvert.c ||
  774. echo 'restore of mcvert.c failed'
  775. Wc_c="`wc -c < 'mcvert.c'`"
  776. test 19826 -eq "$Wc_c" ||
  777.     echo 'mcvert.c: original size 19826, current size' "$Wc_c"
  778. fi
  779. # ============= hqxify.c ==============
  780. if test -f 'hqxify.c' -a X"$1" != X"-c"; then
  781.     echo 'x - skipping hqxify.c (File already exists)'
  782. else
  783. echo 'x - extracting hqxify.c (Text)'
  784. sed 's/^X//' << 'SHAR_EOF' > 'hqxify.c' &&
  785. #include "mactypes.h"
  786. X
  787. /* HQXBUFLEN must be large enough to hold a complete hqx header */
  788. #define HQXBUFLEN 512
  789. byte hqxbuf[HQXBUFLEN + 1], *buf_ptr, *buf_end, *buf_start = hqxbuf + 1;
  790. X
  791. /* Note: line[0] stores the run length character,
  792. X * so line is one greater than MAXLINE  */
  793. #define MAXLINE 2048
  794. byte line[MAXLINE + 1], *line_ptr, *line_end, *line_start = line + 1;
  795. X
  796. /* keep the compiler happy */
  797. #define LINE_START ((char*)(line_start))
  798. X
  799. extern FILE *convert;
  800. extern FILE *debug;
  801. extern FILE *verbose;
  802. X
  803. extern char *cmdname;
  804. X
  805. int line_count, file_count;
  806. int save_state, total_bytes, save_run_length;
  807. word save_accum;
  808. char binfname[BINNAMELEN], hqxfname[BINNAMELEN];
  809. FILE *hqxfile, *binfile;
  810. X
  811. /* This routine reads the header of a hqxed file and appropriately twiddles it,
  812. X    determines if it has CRC problems, creates the .bin file, and puts the info
  813. X    into the .bin file.
  814. X    Output is hqx_datalen, hqx_rsrclen, type, binfname, binfile */
  815. X
  816. hqx_to_bin_hdr(type, hqx_datalen, hqx_rsrclen)
  817. X    char *type;
  818. X    ulong *hqx_datalen, *hqx_rsrclen;
  819. {
  820. X    register byte *hqx_ptr, *hqx_end;
  821. X    register ulong calc_crc;
  822. X    hqx_buf *hqx_block;
  823. X    hqx_header *hqx;
  824. X    info_header info;
  825. X    ulong mtim;
  826. X    short crc;
  827. X
  828. X    extern word magic[];
  829. X    extern char *dir, *ext;
  830. X    extern short calc_mb_crc();
  831. X
  832. X    /* read the hqx header, assuming that I won't exhaust hqxbuf in so doing */
  833. X    fill_hqxbuf();
  834. X    /*
  835. X    * If we are reading multiple files, then we could have the last
  836. X    * unread line of the "previous" file be just a colon (since we are
  837. X    * length driven, and stopped when we processed the expected
  838. X    * lengths), and the prior fill_hqxbuf() call would find it and
  839. X    * return 0, leaving the buffer unfilled.  So, if we have zero
  840. X    * bytes so far, just fill it again.
  841. X     */
  842. X    if (total_bytes == 0) {
  843. X        fprintf(debug,
  844. X            "%s: Note: had to call fix_hqxbuf again in hqx_to_bin_hdr\n",
  845. X            cmdname);
  846. X        fill_hqxbuf();
  847. X    }
  848. X    if (total_bytes < MIN_HQX_HDR) {
  849. X        fprintf(verbose, "%s: %s (%d < %d): bad file format? -- exiting\n",
  850. X            cmdname, "error: hqx_header too short", total_bytes, MIN_HQX_HDR);
  851. X        exit(2);
  852. X    }
  853. X
  854. X    hqx_block = (hqx_buf *) buf_ptr;
  855. X    hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen);
  856. X    hqx_ptr = buf_ptr;
  857. X    hqx_end = (byte *) hqx + sizeof(hqx_header) - 1;
  858. X    calc_crc = 0;
  859. X    while (hqx_ptr < hqx_end)
  860. X        calc_crc = (((calc_crc & 0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
  861. X    calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8];
  862. X    calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8];
  863. X    buf_ptr = hqx_ptr;
  864. X
  865. X    /* stuff the hqx header data into the info header */
  866. X    bzero((char*)&info, sizeof(info_header));
  867. X    info.nlen = hqx_block->nlen;
  868. X    strncpy((char*)info.name, (char*)hqx_block->name, (int)info.nlen);/* name */
  869. X    bcopy((char*)hqx->type, (char*)info.type, 9);       /* type, author, flag */
  870. X    info.flags &= 0x7e;               /* reset lock bit, init bit */
  871. X    if (hqx->protect & 0x40)
  872. X        info.protect = 1;           /* copy protect bit */
  873. X    bcopy((char*)hqx->dlen, (char*)info.dlen, 8);           /* dlen, rlen */
  874. X    mtim = time2mac((ulong)time((long*)0));
  875. X    bcopy((char*)&mtim, (char*)info.mtim, 4);
  876. X    bcopy((char*)&mtim, (char*)info.ctim, 4);
  877. X    info.uploadvers = '\201';
  878. X    info.readvers = '\201';
  879. X
  880. X    /* calculate MacBinary CRC */
  881. X    crc = calc_mb_crc((unsigned char*)&info, 124L, 0);
  882. X    info.crc[0] = (char) (crc >> 8);
  883. X    info.crc[1] = (char) crc;
  884. X
  885. X    /* Create the .bin file and write the info to it */
  886. X    unixify((char*)hqx_block->name);
  887. X    sprintf(binfname, "%s/%s%s", dir, hqx_block->name, ext);
  888. X    fprintf(convert,
  889. X        "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  890. X        hqx_block->name, info.type, info.auth);
  891. X
  892. X    if ((binfile = fopen(binfname, "w")) == NULL)
  893. X        error("Cannot open %s for write", binfname);
  894. X    check_hqx_crc((word)calc_crc, "File header CRC mismatch in %s", binfname);
  895. X    fwrite((char*)&info, sizeof(info), 1, binfile);
  896. X
  897. X    /* Get a couple of items we'll need later */
  898. X    bcopy((char*)info.dlen, (char*)hqx_datalen, 4);
  899. X    *hqx_datalen = mac2long(*hqx_datalen);
  900. X    bcopy((char*)info.rlen, (char*)hqx_rsrclen, 4);
  901. X    *hqx_rsrclen = mac2long(*hqx_rsrclen);
  902. X    bcopy((char*)info.type, (char*)type, 4);
  903. X
  904. X    /* emit useful debugging info */
  905. X    fprintf(debug, "\tdata_len=%10ld\t\ttrsrc_len=%10ld\n",
  906. X        *hqx_datalen, *hqx_rsrclen);
  907. X
  908. }
  909. X
  910. /* This routine reads the header of a bin file and appropriately twiddles it,
  911. X    creates the .hqx file, and puts the info into the .hqx file.
  912. X    Output is hqx_datalen, hqx_rsrclen, type, hqxfname, hqxfile */
  913. X
  914. bin_to_hqx_hdr(hqx_datalen, hqx_rsrclen)
  915. X    ulong *hqx_datalen, *hqx_rsrclen;
  916. {
  917. X    register byte *hqx_ptr, *hqx_end;
  918. X    register ulong calc_crc;
  919. X    hqx_buf *hqx_block;
  920. X    hqx_header *hqx;
  921. X    info_header info;
  922. X    extern word magic[];
  923. X    extern char **hqxnames_left;
  924. X    extern char *ext;
  925. X
  926. X    strcpy(binfname, *hqxnames_left++);
  927. X    if (!(binfile = fopen(binfname, "r"))) {
  928. X        /* Maybe we are supposed to figure out the suffix ourselves? */
  929. X        strcat(binfname, ext);
  930. X        if (!(binfile = fopen(binfname, "r")))
  931. X            error("Cannot open %s for read", binfname);
  932. X    }
  933. X    if (!fread((char*)&info, sizeof(info), 1, binfile))
  934. X        error("Unexpected EOF in header of %s", binfname);
  935. X
  936. X    /* stuff the info header into the hqx header */
  937. X    hqx_block = (hqx_buf *) buf_ptr;
  938. X    hqx_block->nlen = info.nlen;
  939. X    strncpy((char*)hqx_block->name, (char*)info.name, (int)info.nlen);
  940. X    hqx = (hqx_header *) (hqx_block->name + hqx_block->nlen);
  941. X    hqx->version = 0;
  942. X    bcopy((char*)info.type, (char*)hqx->type, 9);   /* type, author, flags */
  943. X    hqx->flags &= 0x7e;               /* reset lock bit, init bit */
  944. X    if (info.protect = 1)
  945. X        hqx->protect = 0;           /* protect bit: 0x40 */
  946. X    else
  947. X        hqx->protect = 0;
  948. X    bcopy((char*)info.dlen, (char*)hqx->dlen, 8);           /* dlen, rlen */
  949. X
  950. X    /* Create the .hqx file and write the info to it */
  951. X    strncpy(hqxfname, (char*)info.name, (int)info.nlen);
  952. X    hqxfname[info.nlen] = '\0';
  953. X    unixify(hqxfname);
  954. X    fprintf(convert,
  955. X        "Converting     %-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  956. X        hqxfname, info.type, info.auth);
  957. X
  958. X    calc_crc = 0;
  959. X    hqx_ptr = (byte *) hqx_block;
  960. X    hqx_end = hqx_ptr + hqx_block->nlen + sizeof(hqx_header);
  961. X    while (hqx_ptr < hqx_end)
  962. X        calc_crc = (((calc_crc & 0xff) << 8) | *hqx_ptr++) ^ magic[calc_crc >> 8];
  963. X    calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8];
  964. X    calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8];
  965. X    buf_ptr = hqx_end;
  966. X    write_hqx_crc((word)calc_crc);
  967. X
  968. X    /* Get a couple of items we'll need later */
  969. X    bcopy((char*)info.dlen, (char*)hqx_datalen, 4);
  970. X    *hqx_datalen = mac2long(*hqx_datalen);
  971. X    bcopy((char*)info.rlen, (char*)hqx_rsrclen, 4);
  972. X    *hqx_rsrclen = mac2long(*hqx_rsrclen);
  973. }
  974. X
  975. X
  976. /* This routine copies bytes from the decoded input stream to the output.  
  977. X    It also pads to a multiple of 128 bytes on the output, which is part
  978. X    of the .bin format */
  979. word
  980. hqx_to_bin_fork(nbytes)
  981. X    register ulong nbytes;
  982. {
  983. X    register byte *cp;
  984. X    register ulong calc_crc;
  985. X    register int c_length;
  986. X    ulong extra_bytes;
  987. X    extern word magic[];
  988. X    long avail = 0;    /* used for internal consistency checking */
  989. X    int wrote;
  990. X
  991. X    extra_bytes = 127 - (nbytes + 127) % 128;    /* pad fork to mult of
  992. X                             * 128 bytes */
  993. X    calc_crc = 0;
  994. X    for (;;) {
  995. X        cp = buf_ptr;
  996. X        c_length = (cp + nbytes > buf_end) ? buf_end - cp : nbytes;
  997. X        /* we can only check readily if we read it here */
  998. X        if (avail && c_length > avail)
  999. X            error("hqx_to_bin_fork: writing %ld too many bytes",
  1000. X                (char*)c_length - avail);
  1001. X        nbytes -= c_length;
  1002. X        wrote = fwrite((char*)cp, sizeof(byte), c_length, binfile);
  1003. X        if (wrote != c_length)
  1004. X            error("hqx_to_bin_fork: fwrite on binfile wrote %ld bytes too few",
  1005. X                (char*)c_length-wrote);
  1006. X        while (c_length--)
  1007. X            calc_crc = (((calc_crc & 0xff) << 8) | *cp++) ^ magic[calc_crc >> 8];
  1008. X        if (!nbytes)
  1009. X            break;
  1010. X        avail = fill_hqxbuf();
  1011. X    }
  1012. X    buf_ptr = cp;
  1013. X    while (extra_bytes--)
  1014. X        putc(0, binfile);
  1015. X    calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8];
  1016. X    calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8];
  1017. X    return (word) calc_crc;
  1018. }
  1019. X
  1020. /* This routine copies bytes from the input stream to the encoded output.  
  1021. X    It also pads to a multiple of 128 bytes on the input, which is part
  1022. X    of the .bin format */
  1023. word
  1024. bin_to_hqx_fork(nbytes)
  1025. X    register ulong nbytes;
  1026. {
  1027. X    register byte *cp;
  1028. X    register ulong calc_crc;
  1029. X    register int c_length;
  1030. X    ulong extra_bytes;
  1031. X    extern word magic[];
  1032. X
  1033. X    extra_bytes = 127 - (nbytes + 127) % 128;    /* pad fork to mult of
  1034. X                             * 128 bytes */
  1035. X    calc_crc = 0;
  1036. X    for (;;) {
  1037. X        cp = buf_ptr;
  1038. X        c_length = (cp + nbytes > buf_end) ? buf_end - cp : nbytes;
  1039. X        nbytes -= c_length;
  1040. X        fread((char*)cp, sizeof(byte), c_length, binfile);
  1041. X        buf_ptr += c_length;
  1042. X        while (c_length--)
  1043. X            calc_crc = (((calc_crc & 0xff) << 8) | *cp++) ^ magic[calc_crc >> 8];
  1044. X        if (!nbytes)
  1045. X            break;
  1046. X        empty_hqxbuf();
  1047. X    }
  1048. X    buf_ptr = cp;
  1049. X
  1050. X    fseek(binfile, (long)extra_bytes, 1);
  1051. X    calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8];
  1052. X    calc_crc = ((calc_crc & 0xff) << 8) ^ magic[calc_crc >> 8];
  1053. X    return (word) calc_crc;
  1054. }
  1055. X
  1056. /* Essentials for Binhex 8to6 run length encoding */
  1057. #define RUNCHAR 0x90
  1058. #define MAXRUN 255
  1059. #define IS_LEGAL <0x40
  1060. #define ISNT_LEGAL >0x3f
  1061. #define DONE 0x7F        /* tr68[':'] = DONE, since Binhex terminator is ':' */
  1062. #define SKIP 0x7E        /* tr68['\n'|'\r'] = SKIP, i. e. end of line char.  */
  1063. X    /* We also treat '\0' as SKIP to handle files without trailing newline */
  1064. #define FAIL 0x7D        /* character illegal in binhex file */
  1065. X
  1066. byte tr86[] =
  1067. "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
  1068. byte tr68[] = {
  1069. X    SKIP, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1070. X    FAIL, FAIL, SKIP, FAIL, FAIL, SKIP, FAIL, FAIL,
  1071. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1072. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1073. X    FAIL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  1074. X    0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, FAIL, FAIL,
  1075. X    0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, FAIL,
  1076. X    0x14, 0x15, DONE, FAIL, FAIL, FAIL, FAIL, FAIL,
  1077. X    0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
  1078. X    0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, FAIL,
  1079. X    0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, FAIL,
  1080. X    0x2C, 0x2D, 0x2E, 0x2F, FAIL, FAIL, FAIL, FAIL,
  1081. X    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, FAIL,
  1082. X    0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, FAIL, FAIL,
  1083. X    0x3D, 0x3E, 0x3F, FAIL, FAIL, FAIL, FAIL, FAIL,
  1084. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1085. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1086. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1087. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1088. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1089. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1090. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1091. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1092. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1093. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1094. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1095. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1096. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1097. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1098. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1099. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1100. X    FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
  1101. };
  1102. X
  1103. /*
  1104. X *  This procedure transparently reads and decodes the hqx input.
  1105. X *  It does run length and 6 to 8 decoding.
  1106. X * Global Input
  1107. X *  buf_start
  1108. X *  line_ptr
  1109. X *  save_*
  1110. X * Global Output
  1111. X *  buf_ptr end of buffer used
  1112. X *  line_ptr
  1113. X *  save_*
  1114. X * Internal
  1115. X *  line":holds the encoded incoming ascii line.
  1116. X *  buf: holds the decoding binary binary.
  1117. X *  buf[-1] holds the character to be repeated for run length encoding.
  1118. X *  As many lines as required are read to fill up buf.
  1119. X */
  1120. #define READING 0
  1121. #define SKIPPING 1
  1122. #define FIND_START_COLON 2
  1123. #define FINDING_COLON 3
  1124. X
  1125. /*
  1126. X * CAUTION: the control flow is quite confusing and full of special
  1127. X * cases; this routine should be rewritten.  But if it ain't broke
  1128. X * (anymore), don't fix it . . .
  1129. X * NO! It's just too ugly to hack anymore!  Next time, rewrite!
  1130. X * It's too bad we can't look for ``(This file ..'' when hunting for a
  1131. X * starting colon, but we don't emit such a line at the head of every
  1132. X * segment, so we can't expect to find one, now, can we?
  1133. X *
  1134. X * We were really too brittle when scanning, since we only
  1135. X * accepted lines which were exactly 64 (HQXLINELEN) characters long.
  1136. X * Fixed in version 1.83
  1137. X */
  1138. /* returns the number of bytes read */
  1139. fill_hqxbuf()
  1140. {
  1141. X    register ulong c, accum;
  1142. X    register int not_in_a_run = TRUE, state68;
  1143. X    register byte *fast_buf, *fast_line;
  1144. X    static int phase = FIND_START_COLON;
  1145. X    long avail;
  1146. X
  1147. X    buf_ptr = fast_buf = buf_start;
  1148. X    fast_line = line_ptr;
  1149. X    state68 = save_state;
  1150. X    accum = save_accum;
  1151. X    if (save_run_length > 0) {
  1152. X        c = save_run_length;
  1153. X        save_run_length = 0;
  1154. X        goto continue_run;
  1155. X    }
  1156. X
  1157. X    while (fast_buf < buf_end) {
  1158. X
  1159. next_char:
  1160. X        if ((c = *fast_line++) ISNT_LEGAL) {
  1161. X            if (c == DONE) {
  1162. X                /* done processing the file, so get out */
  1163. X                /* phase has already been set by read processing */
  1164. X                break;
  1165. X          }
  1166. X
  1167. X    next_line:
  1168. X            if (!fgets(LINE_START, MAXLINE, hqxfile) && !new_in_hqx_file()) {
  1169. X                /*
  1170. X                 * Used to assume if no more input available through error or
  1171. X                 * exhaustion while looking for valid data then must be done.
  1172. X                 * But we are demand driven (now) and if called, must
  1173. X                 * find data.  So we don't silently exit any more.
  1174. X                 */
  1175. X                error("Premature EOF while reading %s", hqxfname);
  1176. X            }
  1177. X            line_ptr = line_start;
  1178. X
  1179. X            fprintf(debug, "DEBUG: input: %s\n", line_start);
  1180. X
  1181. X    scan_line:
  1182. X
  1183. X            /* ensure the the entire line is valid */
  1184. X
  1185. X            fast_line = line_ptr;
  1186. X            while ((*fast_line = tr68[*fast_line]) IS_LEGAL)
  1187. X                fast_line++;
  1188. X
  1189. X            /* grab the stopper */
  1190. X            c = *fast_line;
  1191. X
  1192. X            /* check for validity, transition phases as required */
  1193. X            switch (phase) {
  1194. X
  1195. X            case READING:
  1196. X            case SKIPPING:
  1197. X            case FINDING_COLON:
  1198. X                if (c == SKIP && fast_line > line_ptr) {
  1199. X                    /* the entire line is valid (again), so (resume) reading */
  1200. X                    /* hack: we require the line to be non-empty to make the
  1201. X                     * existing logic work */
  1202. X                    phase = READING;
  1203. X                    break;
  1204. X                }
  1205. X                if (c == DONE && tr68[fast_line[1]] == SKIP) {
  1206. X                    /*
  1207. X                     * valid encoded last line, so
  1208. X                     * set phase for next line, and process this line --
  1209. X                     * we exit the fill-the-buffer loop when the terminal
  1210. X                     * colon is encountered during line processing
  1211. X                     */
  1212. X                    phase = FIND_START_COLON;
  1213. X                    break;
  1214. X                }
  1215. X
  1216. X                /* line is not entirely valid, so do some flavor of skipping */
  1217. X                phase = (phase == FINDING_COLON) ? FIND_START_COLON : SKIPPING;
  1218. X                goto next_line;
  1219. X
  1220. X            case FIND_START_COLON:
  1221. X                if (*line_start == DONE) {
  1222. X                    /* can't transition to READING
  1223. X                     * until know that entire line is valid
  1224. X                     * so transition to intermediate state
  1225. X                     */
  1226. X                    phase = FINDING_COLON;
  1227. X                    /* skip the initial colon */
  1228. X                    line_ptr++;
  1229. X                    goto scan_line;
  1230. X                }
  1231. X                goto next_line;
  1232. X
  1233. X            }
  1234. X
  1235. X            /* we've read in a valid line, so start processing it */
  1236. X            fast_line = line_ptr;
  1237. X            c = *fast_line++;
  1238. X
  1239. X            /*
  1240. X             * Jskud 15Jul92: fix bug reported by Info-Mac Moderator Bill
  1241. X             * regarding case of last line just :
  1242. X             * The line is valid, but it has no data, so don't ingest it.
  1243. X             */
  1244. X
  1245. X            if (c == DONE)
  1246. X                break;
  1247. X
  1248. X            fprintf(debug, "DEBUG: processing line\n");
  1249. X
  1250. X        }
  1251. X
  1252. X        /* Finally, we have the next 6 bits worth of data in "c" as input. */
  1253. X        /* Note: we use "c" as the output of this processing too */
  1254. X        switch (state68++) {
  1255. X        case 0:
  1256. X            accum = c;
  1257. X            goto next_char;
  1258. X        case 1:
  1259. X            accum = (accum << 6) | c;
  1260. X            c = accum >> 4;
  1261. X            break;
  1262. X        case 2:
  1263. X            accum = (accum << 6) | c;
  1264. X            c = (accum >> 2) & 0xff;
  1265. X            break;
  1266. X        case 3:
  1267. X            /* we avoid any miniscule optimizations here
  1268. X             * to maintain parallelism and clarity
  1269. X             * which should enhance program maintainability
  1270. X             */
  1271. X            accum = (accum << 6) | c;
  1272. X            c = accum & 0xff;
  1273. X            state68 = 0;
  1274. X            break;
  1275. X        }
  1276. X        if (not_in_a_run)
  1277. X            if (c != RUNCHAR)
  1278. X                *fast_buf++ = c;
  1279. X            else {
  1280. X                not_in_a_run = FALSE;
  1281. X                goto next_char;
  1282. X            }
  1283. X        else {
  1284. X            /* "c" has the run total length, not just the incremental,
  1285. X               hence the post decrement is correct */
  1286. X            if (c--) {
  1287. X                avail = buf_end - fast_buf;
  1288. X                if (c > avail) {
  1289. X                    save_run_length = c - avail;
  1290. X                    c = avail;
  1291. X                }
  1292. X        continue_run:
  1293. X                {
  1294. X                    register char ch = fast_buf[-1];
  1295. X
  1296. X                    while (c--)
  1297. X                        *fast_buf++ = ch;
  1298. X                }
  1299. X
  1300. X            } else
  1301. X                /* handle special case of 0x9000 => 0x90 */
  1302. X                *fast_buf++ = RUNCHAR;
  1303. X
  1304. X            not_in_a_run = TRUE;
  1305. X        }
  1306. X    }
  1307. X
  1308. X    avail = fast_buf - buf_ptr;
  1309. X    total_bytes += avail;
  1310. X    buf_start[-1] = fast_buf[-1];
  1311. X    line_ptr = fast_line;
  1312. X    save_state = state68;
  1313. X    save_accum = accum;
  1314. X
  1315. X    return avail;
  1316. X
  1317. }
  1318. X
  1319. X
  1320. new_in_hqx_file()
  1321. {
  1322. X    char *hqx_ext;
  1323. X    extern char **hqxnames_left;
  1324. X    int result;
  1325. X
  1326. X    fprintf(debug, "entering new_in_hqx_file ...\n");
  1327. X
  1328. X    if (*hqxnames_left[0] == '\0' || *hqxnames_left[0] == '-') {
  1329. X        result = FALSE;
  1330. X        goto exit;
  1331. X    }
  1332. X
  1333. X    strcpy(hqxfname, *hqxnames_left++);
  1334. X    hqx_ext = hqxfname + strlen(hqxfname) - 4;
  1335. X    if (!strcmp(hqx_ext, ".hqx")) {
  1336. X        if (!freopen(hqxfname, "r", hqxfile))
  1337. X            error("Cannot open %s for read", hqxfname);
  1338. X    } else {
  1339. X        if (!freopen(hqxfname, "r", hqxfile)) {
  1340. X            hqx_ext += 4;
  1341. X            strcpy(hqx_ext, ".hqx");
  1342. X            if (!freopen(hqxfname, "r", hqxfile)) {
  1343. X                error("Cannot open %s for read", hqxfname);
  1344. X            }
  1345. X        }
  1346. X    }
  1347. X    fgets(LINE_START, MAXLINE, hqxfile);
  1348. X    result = TRUE;
  1349. X
  1350. exit:
  1351. X    if (result == TRUE)
  1352. X        fprintf(debug, "... opened %s\n", hqxfname);
  1353. X    else
  1354. X        fprintf(debug, "... nothing to open\n");
  1355. X
  1356. X    return result;
  1357. }
  1358. X
  1359. /*
  1360. X *  This procedure transparently encodes and writes the hqx output.  
  1361. X *  It does run length and 8 to 6 encoding.
  1362. X */
  1363. empty_hqxbuf()
  1364. {
  1365. X    register ulong c, accum, last_c;
  1366. X    register byte *fast_buf, *fast_line;
  1367. X    register int state86, dont_look_for_runs = FALSE, run_length;
  1368. X    extern int maxlines;
  1369. X
  1370. X    run_length = save_run_length;
  1371. X    last_c = buf_start[-1];
  1372. X    fast_buf = buf_start;
  1373. X    fast_line = line_ptr;
  1374. X    state86 = save_state;
  1375. X    accum = save_accum;
  1376. X    while (fast_buf < buf_ptr) {
  1377. X        c = *fast_buf++;
  1378. X        if (dont_look_for_runs)
  1379. X            dont_look_for_runs = FALSE;
  1380. X        else if (last_c == c && run_length < MAXRUN) {
  1381. X            run_length++;
  1382. X            continue;
  1383. X        } else {
  1384. X            if (run_length > 1) {
  1385. X                --fast_buf;
  1386. X                if (run_length == 2 && last_c != RUNCHAR)
  1387. X                    c = last_c;
  1388. X                else {
  1389. X                    c = RUNCHAR;
  1390. X                    *--fast_buf = run_length;
  1391. X                    dont_look_for_runs = TRUE;
  1392. X                }
  1393. X                run_length = 1;
  1394. X            } else
  1395. X                last_c = c;
  1396. X            if (c == RUNCHAR && !dont_look_for_runs) {
  1397. X                *--fast_buf = 0;
  1398. X                dont_look_for_runs = TRUE;
  1399. X            }
  1400. X        }
  1401. X
  1402. X        if (fast_line == line_end) {
  1403. X            if (line_count++ == maxlines)
  1404. X                new_out_hqx_file();
  1405. X            fputs(LINE_START, hqxfile);
  1406. X            fast_line = line_start;
  1407. X        }
  1408. X        switch (state86++) {
  1409. X        case 0:
  1410. X            *fast_line++ = tr86[c >> 2];
  1411. X            accum = (c << 4) & 0x3f;
  1412. X            break;
  1413. X        case 1:
  1414. X            *fast_line++ = tr86[(c >> 4) | accum];
  1415. X            accum = (c << 2) & 0x3f;
  1416. X            break;
  1417. X        case 2:
  1418. X            *fast_line++ = tr86[(c >> 6) | accum];
  1419. X            if (fast_line == line_end) {
  1420. X                if (line_count++ == maxlines)
  1421. X                    new_out_hqx_file();
  1422. X                fputs(LINE_START, hqxfile);
  1423. X                fast_line = line_start;
  1424. X            }
  1425. X            *fast_line++ = tr86[c & 0x3f];
  1426. X            state86 = 0;
  1427. X            break;
  1428. X        }
  1429. X    }
  1430. X    save_run_length = run_length;
  1431. X    buf_start[-1] = last_c;
  1432. X    buf_ptr = buf_start;
  1433. X    line_ptr = fast_line;
  1434. X    save_state = state86;
  1435. X    save_accum = accum;
  1436. }
  1437. X
  1438. new_out_hqx_file()
  1439. {
  1440. X    char filename[NAMELEN + 7];
  1441. X    extern int maxlines;
  1442. X    int rc;
  1443. X
  1444. X    fprintf(hqxfile, "<<< End of Part %2d >>>\n", file_count);
  1445. X    rc = fclose(hqxfile);
  1446. X    if (rc == EOF)
  1447. X        error("Error closing hqxfile", (char*)0);
  1448. X    file_count++;
  1449. X    if (maxlines)
  1450. X        sprintf(filename, "%s%02d.hqx", hqxfname, file_count);
  1451. X    else
  1452. X        sprintf(filename, "%s.hqx", hqxfname);
  1453. X    if ((hqxfile = fopen(filename, "w")) == NULL)
  1454. X        error("Cannot open %s for write", filename);
  1455. X    if (file_count > 1)
  1456. X        fprintf(hqxfile, "<<< Start of Part %2d >>>\n", file_count);
  1457. X    else
  1458. X        fprintf(hqxfile, "(This file must be converted with BinHex 4.0)\n\n");
  1459. X    line_count = 3;
  1460. }
  1461. X
  1462. check_hqx_crc(calc_crc, msg, name)
  1463. X    word calc_crc;
  1464. X    char msg[], name[];
  1465. X
  1466. {
  1467. X    word read_crc;
  1468. X
  1469. X    if (buf_ptr >= buf_end)
  1470. X        fill_hqxbuf();
  1471. X    read_crc = *buf_ptr++ << 8;
  1472. X    if (buf_ptr >= buf_end)
  1473. X        fill_hqxbuf();
  1474. X    read_crc |= *buf_ptr++;
  1475. X    if (read_crc != calc_crc)
  1476. X        error(msg, name);
  1477. }
  1478. X
  1479. write_hqx_crc(calc_crc)
  1480. X    word calc_crc;
  1481. {
  1482. X    if (buf_ptr == buf_end)
  1483. X        empty_hqxbuf();
  1484. X    *buf_ptr++ = calc_crc >> 8;
  1485. X    if (buf_ptr == buf_end)
  1486. X        empty_hqxbuf();
  1487. X    *buf_ptr++ = calc_crc;
  1488. }
  1489. X
  1490. un_hqx(unpit_flag)
  1491. X    int unpit_flag;
  1492. {
  1493. X    char type[4];
  1494. X    ulong hqx_datalen, hqx_rsrclen;
  1495. X    word un_pit();
  1496. X    int unpitting, bytes_read;
  1497. X    word calc_crc;
  1498. X    extern char **hqxnames_left;
  1499. X
  1500. X    hqxfile = fopen("/dev/null", "r");
  1501. X    if (hqxfile == NULL)
  1502. X        error("Cannot open %s for read", "/dev/null");
  1503. X    line_end = line_start + HQXLINELEN;
  1504. X    buf_end = buf_start + HQXBUFLEN;
  1505. X
  1506. X    while (*hqxnames_left[0] != '\0' && *hqxnames_left[0] != '-') {
  1507. X        /* that is, while we still have files to process */
  1508. X        total_bytes = 0;
  1509. X        line_ptr = line_start;
  1510. X        line_ptr[0] = SKIP;
  1511. X        save_state = 0;
  1512. X        save_run_length = 0;
  1513. X
  1514. X        hqx_to_bin_hdr(type, &hqx_datalen, &hqx_rsrclen);    /* binfname */
  1515. X
  1516. X        unpitting = unpit_flag && !strcmp(type, "PIT ");
  1517. X        if (unpitting) {
  1518. X            fclose(binfile);
  1519. X            unlink(binfname);
  1520. X            bytes_read = total_bytes - (buf_end - buf_ptr);
  1521. X            calc_crc = un_pit();
  1522. X            bytes_read = total_bytes - (buf_end - buf_ptr) - bytes_read;
  1523. X            if (bytes_read != hqx_datalen)
  1524. X                fprintf(verbose,
  1525. X                    "Warning - Extraneous characters ignored in %s\n", binfname);
  1526. X        } else {
  1527. X            calc_crc = hqx_to_bin_fork(hqx_datalen);
  1528. X        }
  1529. X        check_hqx_crc(calc_crc, "File data CRC mismatch in %s", binfname);
  1530. X
  1531. X        calc_crc = hqx_to_bin_fork(hqx_rsrclen);
  1532. X        check_hqx_crc(calc_crc, "File rsrc CRC mismatch in %s", binfname);
  1533. X
  1534. X        if (!unpitting)
  1535. X            fclose(binfile);
  1536. X    }
  1537. }
  1538. X
  1539. re_hqx()
  1540. {
  1541. X    word calc_crc;
  1542. X    ulong hqx_datalen, hqx_rsrclen;
  1543. X    extern char **hqxnames_left;
  1544. X    extern int maxlines;
  1545. X    int rc;
  1546. X
  1547. X    line_end = line_start + HQXLINELEN;
  1548. X    buf_end = buf_start + HQXBUFLEN;
  1549. X    while (*hqxnames_left[0] != '-') {
  1550. X        hqxfile = fopen("/dev/null", "w");
  1551. X        if (hqxfile == NULL)
  1552. X            error("Cannot open %s for write", "/dev/null");
  1553. X
  1554. X        /*
  1555. X       * We use the trick of setting our line_count at the limit to
  1556. X       * force an immediate transition on overflow.
  1557. X         */
  1558. X        line_count = maxlines;
  1559. X
  1560. X        file_count = 0;
  1561. X        line_ptr = line_start;
  1562. X        *line_ptr++ = ':';
  1563. X        strcpy((char*)line_end, "\n");
  1564. X        buf_ptr = buf_start;
  1565. X        save_state = 0;
  1566. X        save_run_length = 1;
  1567. X
  1568. X        bin_to_hqx_hdr(&hqx_datalen, &hqx_rsrclen);    /* calculates hqxfname */
  1569. X
  1570. X        /*
  1571. X       * Now that we have hqxfname, start the new file if
  1572. X         * not yet started.  We no longer wait until the output
  1573. X         * buffer overflows, since empty files with short names didn't overflow!
  1574. X         */
  1575. X
  1576. X        if (file_count == 0)
  1577. X            new_out_hqx_file();
  1578. X
  1579. X        calc_crc = bin_to_hqx_fork(hqx_datalen);
  1580. X        write_hqx_crc(calc_crc);
  1581. X
  1582. X        calc_crc = bin_to_hqx_fork(hqx_rsrclen);
  1583. X        write_hqx_crc(calc_crc);
  1584. X        /*
  1585. X       * To end a run and to get the last stray bits,
  1586. X         * temporarily add a char.
  1587. X         */
  1588. X        *buf_ptr = !buf_ptr[-1];
  1589. X        buf_ptr++;
  1590. X        empty_hqxbuf();
  1591. X        /* now toss any extra output character generated */
  1592. X        if (save_state != 2)
  1593. X            --line_ptr;
  1594. X
  1595. X        /* if we're at the end of the line now, write it out */
  1596. X        if (line_ptr == line_end) {
  1597. X            fputs(LINE_START, hqxfile);
  1598. X            line_ptr = line_start;
  1599. X        }
  1600. X
  1601. X        /* paste the trailing colon onto the end of the line */
  1602. X        /* recall that line_ptr points into the line, not at the line */
  1603. X        strcpy((char*)line_ptr, ":\n");
  1604. X        
  1605. X        /* and flush the output buffer */
  1606. X        fputs(LINE_START, hqxfile);
  1607. X
  1608. X        rc = fclose(hqxfile);
  1609. X        if (rc == EOF)
  1610. X            error("Error closing hqxfile", (char*)0);
  1611. X    }
  1612. }
  1613. SHAR_EOF
  1614. chmod 0444 hqxify.c ||
  1615. echo 'restore of hqxify.c failed'
  1616. Wc_c="`wc -c < 'hqxify.c'`"
  1617. test 23244 -eq "$Wc_c" ||
  1618.     echo 'hqxify.c: original size 23244, current size' "$Wc_c"
  1619. fi
  1620. # ============= unpack.c ==============
  1621. if test -f 'unpack.c' -a X"$1" != X"-c"; then
  1622.     echo 'x - skipping unpack.c (File already exists)'
  1623. else
  1624. echo 'x - extracting unpack.c (Text)'
  1625. sed 's/^X//' << 'SHAR_EOF' > 'unpack.c' &&
  1626. #include "mactypes.h"
  1627. X
  1628. extern word magic[];
  1629. extern FILE *output;
  1630. extern char *dir, *ext;
  1631. X
  1632. ulong pit_datalen, pit_rsrclen;
  1633. word hqx_crc, write_pit_fork();
  1634. char pitfname[BINNAMELEN];    /* name of file being unpacked */
  1635. FILE *pitfile;            /* output file */
  1636. X
  1637. branch branchlist[255], *branchptr, *read_tree();
  1638. leaf leaflist[256], *leafptr;
  1639. word Huff_nibble, Huff_bit_count;
  1640. X
  1641. byte(*read_char) (), get_crc_byte(), getHuffbyte();
  1642. X
  1643. word 
  1644. un_pit()
  1645. {
  1646. X    char PitId[4];
  1647. X    int i;
  1648. X    word pit_crc;
  1649. X
  1650. X    hqx_crc = 0;
  1651. X    /* Read and unpack until the PackIt End message is read */
  1652. X    for (;;) {
  1653. X        read_char = get_crc_byte;
  1654. X        for (i = 0; i < 4; i++)
  1655. X            PitId[i] = (char) get_crc_byte();
  1656. X        if (!strncmp(PitId, "PEnd", 4))
  1657. X            break;
  1658. X
  1659. X        if (strncmp(PitId, "PMag", 4) && strncmp(PitId, "PMa4", 4))
  1660. X            error("Unrecognized Packit format message %s", PitId);
  1661. X
  1662. X        if (PitId[3] == '4') {           /* if this file is compressed */
  1663. X            branchptr = branchlist;/* read the Huffman decoding  */
  1664. X            leafptr = leaflist;    /* tree that is on the input  */
  1665. X            Huff_bit_count = 0;    /* and use Huffman decoding   */
  1666. X            read_tree();           /* subsequently               */
  1667. X            read_char = getHuffbyte;
  1668. X        }
  1669. X        read_pit_hdr();               /* also calculates datalen,
  1670. X                            * rsrclen, pitfile, pitfname */
  1671. X        pit_crc = write_pit_fork(pit_datalen, (ulong)0);
  1672. X        pit_crc = write_pit_fork(pit_rsrclen, (ulong)pit_crc);
  1673. X        check_pit_crc(pit_crc, "  File data/rsrc CRC mismatch in %s", pitfname);
  1674. X        fclose(pitfile);
  1675. X    }
  1676. X    hqx_crc = (hqx_crc << 8) ^ magic[hqx_crc >> 8];
  1677. X    hqx_crc = (hqx_crc << 8) ^ magic[hqx_crc >> 8];
  1678. X    return hqx_crc;
  1679. }
  1680. X
  1681. check_pit_crc(calc_crc, msg, name)
  1682. X    word calc_crc;
  1683. X    char msg[], name[];
  1684. X
  1685. {
  1686. X    word read_crc;
  1687. X
  1688. X    read_crc = (*read_char) () << 8;
  1689. X    read_crc |= (*read_char) ();
  1690. X    if (read_crc != calc_crc)
  1691. X        error(msg, name);
  1692. }
  1693. X
  1694. /* This routine reads the header of a packed file and appropriately twiddles it,
  1695. X    determines if it has CRC problems, creates the .bin file, and puts the info
  1696. X    into the .bin file.
  1697. X    Output is pit_datalen, pit_rsrclen, pitfname, pitfile */
  1698. read_pit_hdr()
  1699. {
  1700. X    register int n;
  1701. X    register byte *pit_byte;
  1702. X    register ulong pit_crc;
  1703. X    pit_header pit;
  1704. X    info_header info;
  1705. X    short crc;
  1706. X
  1707. X    extern short calc_mb_crc();
  1708. X
  1709. X    /* read the pit header and compute the CRC */
  1710. X    pit_crc = 0;
  1711. X    pit_byte = (byte *) & pit;
  1712. X    for (n = 0; n < sizeof(pit_header); n++) {
  1713. X        *pit_byte = (*read_char) ();
  1714. X        pit_crc = ((pit_crc & 0xff) << 8)
  1715. X            ^ magic[*pit_byte++ ^ (pit_crc >> 8)];
  1716. X    }
  1717. X
  1718. X    /* stuff the pit header data into the info header */
  1719. X    bzero((char*)&info, sizeof(info_header));
  1720. X    info.nlen = pit.nlen;
  1721. X    strncpy((char*)info.name, (char*)pit.name, (int)pit.nlen);/* name */
  1722. X    bcopy((char*)pit.type, (char*)info.type, 9);  /* type, author, flag */
  1723. X    bcopy((char*)pit.dlen, (char*)info.dlen, 16); /* (d,r)len, (c,m)tim */
  1724. X    info.flags &= 0x7e;               /* reset lock bit, init bit */
  1725. X    if (pit.protect & 0x40)
  1726. X        info.protect = 1;           /* copy protect bit */
  1727. X    info.uploadvers = '\201';
  1728. X    info.readvers = '\201';
  1729. X
  1730. X    /* calculate MacBinary CRC */
  1731. X    crc = calc_mb_crc((unsigned char*)&info, 124L, 0);
  1732. X    info.crc[0] = (char) (crc >> 8);
  1733. X    info.crc[1] = (char) crc;
  1734. X
  1735. X    /* Create the .bin file and write the info to it */
  1736. X    pit.name[pit.nlen] = '\0';
  1737. X    unixify((char*)pit.name);
  1738. X    sprintf(pitfname, "%s/%s%s", dir, pit.name, ext);
  1739. X    fprintf(output,
  1740. X        " %-14s%-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  1741. X        (read_char == get_crc_byte) ? "Unpacking" : "Decompressing",
  1742. X        pit.name, pit.type, pit.auth);
  1743. X    if ((pitfile = fopen(pitfname, "w")) == NULL)
  1744. X        error("  Cannot open %s", pitfname);
  1745. X    check_pit_crc((word)pit_crc, "  File header CRC mismatch in %s", pitfname);
  1746. X    fwrite((char*)&info, sizeof(info_header), 1, pitfile);
  1747. X
  1748. X    /* Get a couple of items we'll need later */
  1749. X    bcopy((char*)pit.dlen, (char*)&pit_datalen, 4);
  1750. X    pit_datalen = mac2long(pit_datalen);
  1751. X    bcopy((char*)pit.rlen, (char*)&pit_rsrclen, 4);
  1752. X    pit_rsrclen = mac2long(pit_rsrclen);
  1753. }
  1754. X
  1755. /* This routine copies bytes from the decoded input stream to the output
  1756. X    and calculates the CRC.  It also pads to a multiple of 128 bytes on the
  1757. X    output, which is part of the .bin format */
  1758. word 
  1759. write_pit_fork(nbytes, calc_crc)
  1760. X    register ulong nbytes;
  1761. X    register ulong calc_crc;
  1762. {
  1763. X    register ulong b;
  1764. X    int extra_bytes;
  1765. X
  1766. X    extra_bytes = 127 - (nbytes + 127) % 128;    /* pad fork to mult of
  1767. X                             * 128 bytes */
  1768. X    while (nbytes--) {
  1769. X        b = (*read_char) ();
  1770. X        calc_crc = ((calc_crc & 0xff) << 8) ^ magic[b ^ (calc_crc >> 8)];
  1771. X        putc((char)b, pitfile);
  1772. X    }
  1773. X    while (extra_bytes--)
  1774. X        putc(0, pitfile);
  1775. X    return (word) calc_crc;
  1776. }
  1777. X
  1778. /* This routine recursively reads the compression decoding data.
  1779. X   It appears to be Huffman compression.  Every leaf is represented
  1780. X   by a 1 bit, then the byte it represents.  A branch is represented
  1781. X   by a 0 bit, then its zero and one sons */
  1782. branch *
  1783. read_tree()
  1784. {
  1785. X    register branch *branchp;
  1786. X    register leaf *leafp;
  1787. X    register ulong b;
  1788. X
  1789. X    if (!Huff_bit_count--) {
  1790. X        Huff_nibble = get_crc_byte();
  1791. X        Huff_bit_count = 7;
  1792. X    }
  1793. X    if ((Huff_nibble <<= 1) & 0x0100) {
  1794. X        leafp = leafptr++;
  1795. X        leafp->flag = 1;
  1796. X        b = get_crc_byte();
  1797. X        leafp->data = Huff_nibble | (b >> Huff_bit_count);
  1798. X        Huff_nibble = b << (8 - Huff_bit_count);
  1799. X        return (branch *) leafp;
  1800. X    } else {
  1801. X        branchp = branchptr++;
  1802. X        branchp->flag = 0;
  1803. X        branchp->zero = read_tree();
  1804. X        branchp->one = read_tree();
  1805. X        return branchp;
  1806. X    }
  1807. }
  1808. X
  1809. /* This routine returns the next 8 bits.  It finds the byte in the
  1810. X   Huffman decoding tree based on the bits from the input stream. */
  1811. byte 
  1812. getHuffbyte()
  1813. {
  1814. X    register branch *branchp;
  1815. X
  1816. X    branchp = branchlist;
  1817. X    while (!branchp->flag) {
  1818. X        if (!Huff_bit_count--) {
  1819. X            Huff_nibble = get_crc_byte();
  1820. X            Huff_bit_count = 7;
  1821. X        }
  1822. X        branchp = ((Huff_nibble <<= 1) & 0x0100) ? branchp->one : branchp->zero;
  1823. X    }
  1824. X    return ((leaf *) branchp)->data;
  1825. }
  1826. X
  1827. /* This routine returns the next byte on the .hqx input stream, hiding
  1828. X    most file system details at a lower level.  .hqx CRC is maintained
  1829. X    here */
  1830. byte 
  1831. get_crc_byte()
  1832. {
  1833. X    register ulong c;
  1834. X    extern byte *buf_ptr, *buf_end;
  1835. X
  1836. X    if (buf_ptr == buf_end)
  1837. X        fill_hqxbuf();
  1838. X    c = *buf_ptr++;
  1839. X    hqx_crc = ((hqx_crc << 8) | c) ^ magic[hqx_crc >> 8];
  1840. X    return (byte) c;
  1841. }
  1842. SHAR_EOF
  1843. chmod 0444 unpack.c ||
  1844. echo 'restore of unpack.c failed'
  1845. Wc_c="`wc -c < 'unpack.c'`"
  1846. test 6096 -eq "$Wc_c" ||
  1847.     echo 'unpack.c: original size 6096, current size' "$Wc_c"
  1848. fi
  1849. # ============= mactypes.h ==============
  1850. if test -f 'mactypes.h' -a X"$1" != X"-c"; then
  1851.     echo 'x - skipping mactypes.h (File already exists)'
  1852. else
  1853. echo 'x - extracting mactypes.h (Text)'
  1854. sed 's/^X//' << 'SHAR_EOF' > 'mactypes.h' &&
  1855. #include <stdio.h>
  1856. #include <sys/types.h>
  1857. #include <sys/dir.h>
  1858. #include <sys/stat.h>
  1859. X
  1860. #ifdef TIMEVAL
  1861. #  include <sys/param.h>
  1862. #  include <sys/time.h>
  1863. #else
  1864. #  include <sys/timeb.h>
  1865. #endif
  1866. X
  1867. /* Useful, though not particularly Mac related, values */
  1868. typedef unsigned char byte;     /* one byte, obviously */
  1869. typedef unsigned short word;    /* must be 2 bytes */
  1870. X
  1871. #ifndef ULONG
  1872. X    typedef unsigned long ulong; /* 4 bytes */
  1873. #endif
  1874. X
  1875. /* declarations to keep lint informed */
  1876. char *calloc();
  1877. #include <string.h>
  1878. void exit();
  1879. long time();
  1880. ulong time2mac();
  1881. X
  1882. #define TRUE  1
  1883. #define FALSE 0
  1884. #define CR 0x0d
  1885. #define LF 0x0a
  1886. X
  1887. /* Compatibility issues */
  1888. #ifdef BSD
  1889. #define mac2word (word) ntohs
  1890. #define mac2long (ulong) ntohl
  1891. #define word2mac (word) htons
  1892. #define long2mac (ulong) htonl
  1893. #else
  1894. #define mac2word
  1895. #define mac2long
  1896. #define word2mac
  1897. #define long2mac
  1898. #endif
  1899. X
  1900. #ifdef MAXNAMLEN                /* 4.2 BSD, stdio.h */
  1901. #define SYSNAMELEN MAXNAMLEN
  1902. #else
  1903. #define SYSNAMELEN DIRSIZ
  1904. #endif
  1905. X
  1906. #define NAMELEN 63              /* maximum legal Mac file name length */
  1907. #define BINNAMELEN 68           /* NAMELEN + len(".bin\0") */
  1908. X
  1909. /* Format of a bin file:
  1910. A bin file is composed of 128 byte blocks.  The first block is the
  1911. info_header (see below).  Then comes the data fork, null padded to fill the
  1912. last block.  Then comes the resource fork, padded to fill the last block.  A
  1913. proposal to follow with the text of the Get Info box has not been implemented,
  1914. to the best of my knowledge.  Version, zero1 and zero2 are what the receiving
  1915. program looks at to determine if a MacBinary transfer is being initiated.
  1916. */
  1917. typedef struct {                /* info file header (128 bytes). Unfortunately,
  1918. X                                 * these longs don't align to word boundaries */
  1919. X
  1920. /* decimal offset */
  1921. X
  1922. /* 000 */
  1923. X        byte version;           /* there is only a version 0 at this time */
  1924. /* 001 */
  1925. X        byte nlen;              /* Length of filename. */
  1926. /* 002 */
  1927. X        byte name[NAMELEN];     /* Filename (only 1st nlen are significant) */
  1928. /* 065 */
  1929. X        byte type[4];           /* File type. */
  1930. /* 069 */
  1931. X        byte auth[4];           /* File creator. */
  1932. /* 073 */
  1933. X        byte flags;             /* file flags: LkIvBnSyBzByChIt */
  1934. X                                /* Locked, Invisible,Bundle, System */
  1935. X                                /* Bozo, Busy, Changed, Init */
  1936. /* 074 */
  1937. X        byte zero1;
  1938. /* 075 */
  1939. X        byte icon_vert[2];      /* Vertical icon position within window */
  1940. /* 077 */
  1941. X        byte icon_horiz[2];     /* Horizontal icon postion in window */
  1942. /* 079 */
  1943. X        byte window_id[2];      /* Window or folder ID. */
  1944. /* 081 */
  1945. X        byte protect;           /* = 1 for protected file, 0 otherwise */
  1946. /* 082 */
  1947. X        byte zero2;
  1948. /* 083 */
  1949. X        byte dlen[4];           /* Data Fork length (bytes) -   most sig.  */
  1950. /* 087 */
  1951. X        byte rlen[4];           /* Resource Fork length         byte first */
  1952. /* 091 */
  1953. X        byte ctim[4];           /* File's creation date. */
  1954. /* 095 */
  1955. X        byte mtim[4];           /* File's "last modified" date. */
  1956. /* 099 */
  1957. X        byte ilen[2];           /* GetInfo message length */
  1958. /* 101 */
  1959. X        byte flags2;            /* Finder flags, bits 0-7 */
  1960. /* 102 */
  1961. X        byte unused[14];
  1962. /* 116 */
  1963. X        byte packlen[4];        /* length of total files when unpacked */
  1964. /* 120 */
  1965. X        byte headlen[2];        /* length of secondary header */
  1966. /* 122 */
  1967. X        byte uploadvers;        /* Version of MacBinary II that the uploading
  1968. X                                 * program is written for */
  1969. /* 123 */
  1970. X        byte readvers;          /* Minimum MacBinary II version needed to read
  1971. X                                 * this file */
  1972. /* 124 */
  1973. X        byte crc[2];            /* CRC of the previous 124 bytes */
  1974. /* 126 */
  1975. X        byte padding[2];        /* two trailing unused bytes */
  1976. /* 128 */
  1977. }      info_header;
  1978. X
  1979. /* The *.info file of a MacTerminal file transfer either has exactly this
  1980. structure or has the protect bit in bit 6 (near the sign bit) of byte zero1.
  1981. The code I have for macbin suggests the difference, but I'm not so sure */
  1982. X
  1983. /*
  1984. X * Format of a hqx file:
  1985. X * (but see also binhex-40-specs.txt for legal variations)
  1986. X * 
  1987. X * It begins with a line that begins "(This file" and the rest is 64
  1988. X * character lines (except possibly the last, and not including
  1989. X * newlines) where the first begins and the last ends with a colon.
  1990. X * The characters between colons should be only from the set in tr86,
  1991. X * below, each of which corresponds to 6 bits of data.  Once that is
  1992. X * translated to 8 bit bytes, you have the real data, except that the
  1993. X * byte 0x90 may indicate, if the following character is nonzero, that
  1994. X * the previous byte is to be repeated 1 to 255 times all together
  1995. X * (that is, the count following 0x90 contains the total run length,
  1996. X * not the marginal repeat count).  The byte 0x90 is represented by
  1997. X * 0x9000.  The information in the file is the hqx_buf (see below), a
  1998. X * CRC word, the data fork, a CRC word, the resource fork, and a CRC
  1999. X * word.  There is considerable confusion about the flags.  An
  2000. X * official looking document unclearly states that the init bit is
  2001. X * always clear, as is the following byte.  The experience of others
  2002. X * suggests, however, that this is not the case.
  2003. X */
  2004. X
  2005. /* NOTE:
  2006. X * Jskud 25Jun92
  2007. X
  2008. X * a hqx file has no date/time information, and a binary constructed
  2009. X * from a hqx file will use the current time; therefore, reconverting
  2010. X * a hqx file repeatedly will generate different bin files!
  2011. X
  2012. X * The "flags" byte can change when refetched, for example, whether or
  2013. X * not the init bit is set (that is, the Finder has "seen" the file);
  2014. X * this can affect the hqx file, including the run length encoding, so
  2015. X * the hqx files can look quite different, although the actual
  2016. X * difference is miniscule; also, the init bit difference will not be
  2017. X * present when the hqx file is converted to a bin file, since both the
  2018. X * locked and init bits are cleared on bin file creation.
  2019. X
  2020. X * Because we've experienced this "spurious" difference, and since
  2021. X * the init bit is only thought meaningful when running on the Mac,
  2022. X * and to establish symmetry between bin file creation and hqx file
  2023. X * creation, we unconditionally clear the init and locked bits when
  2024. X * creating the hqx file.
  2025. X
  2026. X */
  2027. X
  2028. #define HQXLINELEN 64
  2029. typedef struct {
  2030. /* decimal offset */
  2031. /* 000 */
  2032. X        byte version;           /* there is only a version 0 at this time */
  2033. /* 001 */
  2034. X        byte type[4];           /* File type. */
  2035. /* 005 */
  2036. X        byte auth[4];           /* File creator. */
  2037. /* 009 */
  2038. X        byte flags;             /* file flags: LkIvBnSyBzByChIt */
  2039. /* 010 */
  2040. X        byte protect;           /* ?Pr??????, don't know what ? bits mean */
  2041. /* 011 */
  2042. X        byte dlen[4];           /* Data Fork length (bytes) -   most sig.  */
  2043. /* 015 */
  2044. X        byte rlen[4];           /* Resource Fork length         byte first */
  2045. /* 019 */
  2046. X        byte bugblank;          /* to fix obscure sun 3/60 problem that always
  2047. X                                 * makes sizeof(hqx_header) even */
  2048. /* 020 */
  2049. }      hqx_header;
  2050. X
  2051. typedef struct {                /* hqx file header buffer (includes file name) */
  2052. X        byte nlen;              /* Length of filename. */
  2053. X        byte name[NAMELEN];     /* Filename: only nlen actually appear */
  2054. X        hqx_header all_the_rest;/* and all the rest follows immediately */
  2055. }      hqx_buf;
  2056. X
  2057. /* every valid hqx header is at least this long */
  2058. #define MIN_HQX_HDR (sizeof(hqx_header) + 2)
  2059. X
  2060. /*
  2061. X *    The minimum number of hqx_lines in a file to ensure that we have
  2062. X *    enough lines to emit the entire header before starting a new file.
  2063. X * + 1 is for rounding, + 2 is for "(This file " and the blank line.
  2064. X */
  2065. #define MIN_HQX_LINES (sizeof(hqx_buf) * 4 / 3 / HQXLINELEN + 1 + 2)
  2066. X
  2067. X
  2068. /* Format of a Packit file:
  2069. Repeat the following sequence for each file in the Packit file:
  2070. X    4 byte identifier ("PMag" = not compressed, "Pma4" = compressed)
  2071. X    320 byte compression data (if compressed file)
  2072. X        = preorder transversal of Huffman tree
  2073. X        255 0 bits corresponding to nonleaf nodes
  2074. X        256 1 bits corresponding to leaf nodes
  2075. X        256 bytes associating leaf nodes with bytes
  2076. X        1   completely wasted bit
  2077. X    92 byte header (see pit_header below) *
  2078. X    2 bytes CRC word for header *
  2079. X    data fork (length from header) *
  2080. X    resource fork (length from header) *
  2081. X    2 bytes CRC word for forks *
  2082. X
  2083. Last file is followed by the 4 byte Ascii string, "Pend", and then the EOF.
  2084. The CRC calculations differ from those in the binhex format.
  2085. X
  2086. * these are in compressed form if compression is on for the file
  2087. X
  2088. */
  2089. X
  2090. typedef struct {                /* Packit file header (92 bytes) */
  2091. X        byte nlen;              /* Length of filename. */
  2092. X        byte name[NAMELEN];     /* Filename (only 1st nlen are significant) */
  2093. X        byte type[4];           /* File type. */
  2094. X        byte auth[4];           /* File creator. */
  2095. X        byte flags;             /* file flags: LkIvBnSyBzByChIt */
  2096. X        byte zero1;
  2097. X        byte protect;           /* = 1 for protected file, 0 otherwise */
  2098. X        byte zero2;
  2099. X        byte dlen[4];           /* Data Fork length (bytes) -   most sig.  */
  2100. X        byte rlen[4];           /* Resource Fork length         byte first */
  2101. X        byte ctim[4];           /* File's creation date. */
  2102. X        byte mtim[4];           /* File's "last modified" date. */
  2103. }      pit_header;
  2104. X
  2105. /* types for constructing the Huffman tree */
  2106. typedef struct branch_st {
  2107. X        byte flag;
  2108. X        struct branch_st *one, *zero;
  2109. }         branch;
  2110. X
  2111. typedef struct leaf_st {
  2112. X        byte flag;
  2113. X        byte data;
  2114. }       leaf;
  2115. SHAR_EOF
  2116. chmod 0444 mactypes.h ||
  2117. echo 'restore of mactypes.h failed'
  2118. Wc_c="`wc -c < 'mactypes.h'`"
  2119. test 9603 -eq "$Wc_c" ||
  2120.     echo 'mactypes.h: original size 9603, current size' "$Wc_c"
  2121. fi
  2122. # ============= Makefile ==============
  2123. if test -f 'Makefile' -a X"$1" != X"-c"; then
  2124.     echo 'x - skipping Makefile (File already exists)'
  2125. else
  2126. echo 'x - extracting Makefile (Text)'
  2127. sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
  2128. CSOURCES = mcvert.c hqxify.c unpack.c
  2129. HSOURCES = mactypes.h
  2130. SOURCES = $(CSOURCES) $(HSOURCES) Makefile
  2131. sharSOURCES = $(SOURCES) mcvert.1
  2132. OBJECTS = mcvert.o hqxify.o unpack.o
  2133. ALL = mcvert mcvert.man
  2134. CLEAN = $(OBJECTS) $(ALL)
  2135. X
  2136. VERSION=183
  2137. X
  2138. BIN = .
  2139. X
  2140. ## Last Defintion Wins ##
  2141. X
  2142. ## Machine CFLAGS
  2143. CFLAGS_M= -DTIMEVAL            # for machines without <timeb.h> and ftime()
  2144. CFLAGS_M= -DULONG                # for machines with ulong pre-defined (eg, SGI)
  2145. CFLAGS_M= -DTIMEVAL -DULONG    # eg, for A/UX
  2146. CFLAGS_M=                        # for many machines (eg, HP-UX, SunOS)
  2147. X
  2148. ## Debugging/optimization CFLAGS
  2149. CFLAGS_D = -g                # debugging
  2150. CFLAGS_D = -O                # optimization
  2151. X
  2152. ## All CFLAGS
  2153. CFLAGS=$(CFLAGS_M) $(CFLAGS_D)
  2154. X
  2155. all: $(ALL)
  2156. X
  2157. mcvert: $(OBJECTS)
  2158. X    $(CC) $(CFLAGS) $(OBJECTS) -o $(BIN)/mcvert
  2159. X
  2160. lint: $(HSOURCES) $(CSOURCES)
  2161. X    lint $(CSOURCES)
  2162. X
  2163. $(OBJECTS): mactypes.h Makefile
  2164. X
  2165. print: $(SOURCES)
  2166. X    lpr -p -P$(PRINTER) $(SOURCES)
  2167. X
  2168. shar : mcvert-$(VERSION).shar
  2169. mcvert-$(VERSION).shar : $(sharSOURCES)
  2170. X    shar $(sharSOURCES) > $@
  2171. X
  2172. clean:
  2173. X    rm -f $(CLEAN)
  2174. X
  2175. mcvert.man: mcvert.1
  2176. X    nroff -man mcvert.1 | sed 's/.//g' > $@
  2177. mcvert.ps: mcvert.1
  2178. X    groff -man mcvert.1 > $@
  2179. SHAR_EOF
  2180. chmod 0444 Makefile ||
  2181. echo 'restore of Makefile failed'
  2182. Wc_c="`wc -c < 'Makefile'`"
  2183. test 1108 -eq "$Wc_c" ||
  2184.     echo 'Makefile: original size 1108, current size' "$Wc_c"
  2185. fi
  2186. # ============= mcvert.1 ==============
  2187. if test -f 'mcvert.1' -a X"$1" != X"-c"; then
  2188.     echo 'x - skipping mcvert.1 (File already exists)'
  2189. else
  2190. echo 'x - extracting mcvert.1 (Text)'
  2191. sed 's/^X//' << 'SHAR_EOF' > 'mcvert.1' &&
  2192. .TH MCVERT LOCAL "03Aug92"
  2193. .UC 4.2
  2194. .SH NAME
  2195. mcvert \- BinHex 4.0 to MacBinary file conversion utility
  2196. .SH SYNOPSIS
  2197. .B mcvert
  2198. { [options] name ... } ...
  2199. .br
  2200. .SH DESCRIPTION
  2201. The
  2202. .I mcvert
  2203. program translates files between MacBinary format and
  2204. other formats often used in exchanging Macintosh files.
  2205. See
  2206. .I FILE FORMATS
  2207. below for a description of the file formats supported.
  2208. .SH PARAMETERS
  2209. The defaults for the parameters are
  2210. .RB - xDqv :
  2211. convert BinHex4.0 files
  2212. .RB ( x )
  2213. to MacBinary files
  2214. .RB ( D ),
  2215. bypass automatic unpacking of PIT files
  2216. .RB ( q ),
  2217. and provide a verbose level of output
  2218. .RB ( v ).
  2219. .SH "OPTIONS"
  2220. All the options, other than
  2221. .I "FORMAT OPTIONS"
  2222. described below, are listed here.
  2223. XFrom each set, one and only one alternative is active for any one file.
  2224. .TP
  2225. .B U | D
  2226. When option 'U' is selected, the conversion that takes place is the one suitable
  2227. for Uploading files.  That is, the conversion is from MacBinary to something
  2228. else when 'U' is selected.  Conversely, option 'D', as in Download,
  2229. converts from something to MacBinary.
  2230. .TP
  2231. .B p | q
  2232. If a BinHex to MacBinary conversion is taking place and option 'p' is selected,
  2233. any file of type "PIT "
  2234. will be unpacked into its constituent parts.  This option does not recursively
  2235. unpack "PIT " files packed in "PIT " files.
  2236. If a MacBinary to BinHex conversion is taking place, this option is currently
  2237. ignored.
  2238. .TP
  2239. .B
  2240. S | s | V | v
  2241. Normally,
  2242. .I mcvert
  2243. prints to stderr information about the files it is creating.
  2244. Selecting option 'S', as in Silent, disables all such reporting.
  2245. Option 's', as in silent, disables all but the "Converting ..." messages.
  2246. Option 'V', for very Verbose, displays debugging information as well.
  2247. Option 'v', as in verbose, emits generally useful information.
  2248. .SH "FILE FORMATS"
  2249. The primary formats in which Macintosh files are represented on non-Macs are:
  2250. .TP
  2251. .B MacBinary:
  2252. An eight bit wide representation of the data and resource forks of a Mac
  2253. file and of relevant Finder information, MacBinary files are recognized
  2254. as "special" by several Macintosh terminal emulators.  These emulators,
  2255. using Kermit or Xmodem or any other file transfer protocol, can separate
  2256. the incoming file into forks and appropriately modify the Desktop to display
  2257. icons, types, creation dates, and the like.
  2258. .TP
  2259. .B BinHex 4.0:
  2260. A seven bit wide representation of a Mac file with CRC error checking,
  2261. BinHex 4.0 files are designed for communication of Mac files over long
  2262. distance, possibly noisy, seven bit wide paths.
  2263. .TP
  2264. .B PackIt:
  2265. PackIt files are actually representations of collections of Mac files, possibly
  2266. Huffman compressed.  Packing many small related files together before
  2267. a MacBinary transfer or a translation to BinHex 4.0 is common practice.
  2268. .TP
  2269. .B Text:
  2270. A Macintosh ends each line of a plain text file with a carriage return
  2271. character (^M), rather than the newline character (^J) that some systems
  2272. seem to prefer.  Moreover, a MacBinary file has prepended Finder information
  2273. that non-Macintoshes don't need.
  2274. .TP
  2275. .B Data, Rsrc:
  2276. A Data or Rsrc file is the exact copy of the data or resource fork of a
  2277. Macintosh file.
  2278. .SH "FORMAT OPTIONS"
  2279. Exactly one of the following selections may be specified for an input name:
  2280. .TP
  2281. .B x
  2282. BinHex 4.0 - files in the MacBinary format are translated to BinHex
  2283. files, or vice versa.  The name argument may be the name of a file to be
  2284. converted or a basename to which an appropriate suffix must be appended
  2285. to get a filename.  If the conversion is from Binhex 4.0 to MacBinary,
  2286. several files may comprise the BinHex representation of the Mac file.
  2287. Rather than manually concatenate the files and manually delete mail
  2288. headers and other extraneous garbage, one may specify the names of the
  2289. files in order and
  2290. .I mcvert
  2291. will do the concatenating and deleting.  Conversely, in converting
  2292. a MacBinary file to BinHex 4.0 format for mailing over long distances,
  2293. one may be restricted to mail messages of no greater that some fixed
  2294. length.  In this case,
  2295. .I mcvert
  2296. can automatically divide the BinHex file into pieces and label each
  2297. piece appropriately.
  2298. For details on automatically segmenting files, see the description of the
  2299. .B MAC_LINE_LIMIT
  2300. environment variable below.
  2301. .TP
  2302. .B r
  2303. Resource - files in the MacBinary format with empty data forks
  2304. and nonempty resource forks are made from ordinary data files, or vice versa.
  2305. .TP
  2306. .B d
  2307. Data - files in the MacBinary format with nonempty data forks
  2308. and empty resource forks are made from ordinary data files, or vice versa.
  2309. .TP
  2310. .B u | h
  2311. Text - files in the MacBinary format with nonempty data forks
  2312. and empty resource forks are made from ordinary data files, or vice versa.
  2313. The newly created MacBinary file has creator field given by
  2314. the MAC_EDITOR environment variable.
  2315. Option 'u', for usual, performs conversion.
  2316. Option 'h', for host, performs no conversion.
  2317. When converting,
  2318. Unix newline
  2319. characters are interchanged with MacIntosh carriage return
  2320. characters.
  2321. .PP
  2322. .SH "ENVIRONMENT VARIABLES"
  2323. There are four environment variables one may use to customize 
  2324. the behavior of
  2325. .I mcvert
  2326. slightly.
  2327. .TP
  2328. .B MAC_EDITOR
  2329. The creator of MacBinary text files produced with options -uD.  
  2330. The default is MACA, the creator type of MacWrite.
  2331. .TP
  2332. .B MAC_DLOAD_DIR
  2333. The MacBinary files created when option -D is selected are placed in this
  2334. directory.  The default is ".", the current working directory.
  2335. .TP
  2336. .B MAC_EXT
  2337. The MacBinary files created when option -D is selected are named according
  2338. to the filename field stored in the file header, with the name extended by
  2339. this suffix.  The default is ".bin".
  2340. .TP
  2341. .B MAC_LINE_LIMIT
  2342. The BinHex files created when option -U is selected may be no longer than
  2343. this many lines long.  Files that would otherwise exceed this line limit
  2344. are broken up into several files with numbers embedded into their file 
  2345. names to show their order.  Each such file has "Start of part x" and "End
  2346. of part x" messages included where appropriate.
  2347. .SH BUGS
  2348. It should be possible to discard bad input now and successfully translate
  2349. good input later, but bad input mostly just causes immediate termination.
  2350. .PP
  2351. A more diligent person would support BinHex 3.0 and BinHex 2.0 and BinHex
  2352. 5000.0 B. C., but I've never seen anyone use them in three years.  A
  2353. more diligent person would also do something for users of macget and
  2354. macput, but hopefully someone will make those programs support the
  2355. MacBinary file protocol.
  2356. .PP
  2357. The rules for when files are suffixed with extentions
  2358. like .rsrc and .data are not obvious or are unreasonable.
  2359. For example, when converting from MacBinary to
  2360. resource, data, or text, the suffix is only appended if the non
  2361. suffixed version of the file is readable.  This can lead to anomalies.
  2362. For example, if there is a file called foo.bin which is the MacBinary
  2363. representation for a file called foo, and there is no file named foo,
  2364. then the first mcvert -rU foo will create foo, yet subsequent mcvert -rU foo
  2365. requests will create foo.rsrc.
  2366. .SH SEE ALSO
  2367. xbin(1), macget(1), macput(1), xmodem(1), kermit(1)
  2368. .SH AUTHORS
  2369. Doug Moore, Cornell University Computer Science.  Based upon
  2370. .I xbin
  2371. by Dave Johnson, Brown University, as modified by Guido van Rossum, and upon
  2372. .I unpit
  2373. by Allan G. Weber, as well as upon correspondence with several helpful
  2374. readers of USENET.
  2375. Joseph P. Skudlarek (Jskud@std.mentorg.com) made numerous maintenance releases.
  2376. Also, see the comments in mcvert.c for additional supporting characters.
  2377. SHAR_EOF
  2378. chmod 0444 mcvert.1 ||
  2379. echo 'restore of mcvert.1 failed'
  2380. Wc_c="`wc -c < 'mcvert.1'`"
  2381. test 7376 -eq "$Wc_c" ||
  2382.     echo 'mcvert.1: original size 7376, current size' "$Wc_c"
  2383. fi
  2384. exit 0
  2385.  
  2386.  
  2387.